Instruments & Automation Test in iOS - Mac OS
Lời nói đầu Thế giới ngày nay, có rất nhiều công cụ sẵn sàng được sử dụng để tự động Test những ứng dụng mà bạn viết. Một vài công cụ được duy trì thông qua mô hình mã nguồn mở, nhưng nó cũng là những gì cốt lõi đã được cung cấp bởi Apple. Với mỗi bản phát hành mới của iOS SDK, Apple tiếp tục ...
Lời nói đầu
Thế giới ngày nay, có rất nhiều công cụ sẵn sàng được sử dụng để tự động Test những ứng dụng mà bạn viết. Một vài công cụ được duy trì thông qua mô hình mã nguồn mở, nhưng nó cũng là những gì cốt lõi đã được cung cấp bởi Apple. Với mỗi bản phát hành mới của iOS SDK, Apple tiếp tục thể hiện cam kết của họ đối với việc cải thiện các công cụ sẵn có cho các nhà phát triển để kiểm tra mã họ viết. Đối với các nhà phát triển ứng dụng iOS mới thì các công cụ của Apple là nơi rất tốt để bắt đầu.
1. Giới thiệu về Instruments:
Instruments là một công cụ phân tích hiệu năng và kiểm thử cho iOS và Mac OS (Được tích hợp trong ứng dụng Xcode - được dùng để phát triển ứng dụng cho iOS và Mac OS). Đây là một công cụ linh hoạt và mạnh mẽ giúp ta theo dấu process (của logic trong ứng dụng), thu thập dữ liệu và khảo sát những dữ liệu đã thu thập được. Với phương pháp này Instruments sẽ giúp ta hiểu được hành vi của cả người dùng lẫn hệ điều hành. Trong phạm vi bài viết này chúng ta sẽ tìm hiểu cụ thể hơn về cách mà Instruments tự động tương tác với UI của iOS app và cách ứng dụng chúng để xây dựng test case.
Với ứng dụng iOS, để có thể tương tác với UI một cách tự động ta sẽ gặp phải trở ngại về bảo mật của hệ điều hành. Nhưng ứng dụng hỗ trợ tự động tương tác với UI thường phải chạy trên những thiết bị đã được jailbreak, chưa kể tới việc hệ điều hành mới ra đời sẽ cần một khoảng thời gian nhất định để có thể có phương pháp jailbreak mới. Nhưng với Instruments, được tích hợp sẵn trong Xcode từ phiên bản 3.0 trở đi, ta có thể tương tác với UI của ứng dụng (do cá nhân hoặc tổ chức của ta phát triển - đồng nghĩa với việc cần có certificate và provisioning của thiết bị sử dụng để test). Khi sử dụng test tự động, đội ngũ của chúng ta sẽ có thời gian để làm những việc khác. Tuy nhiên ta sẽ phải dành chút thời gian để viết script cho test case của ứng dụng trước đã.
Ta có thể sử dụng tính năng Automation trong Instruments để tự động tương tác với UI trong ứng dụng thông qua những đoạn script đã viết. (Đồng nghĩa với việc 1 test case chỉ phải viết script 1 lần nhưng được sử dụng để test nhiều lần ngay khi phát triển ứng dụng hay những bản nâng cấp sau). Những đoạn script này sẽ được chạy bên ngoài ứng dụng (đang cần test) và mô phỏng những tương tác của người dùng đối với ứng dụng bằng cách sử dụng UI Automation API (một tập các Java Script API), đồng thời chúng sẽ ghi lại log của quá trình tương tác lên trên máy tính.
Ngoài ra ta có thể tích hợp Automation với những tính năng khác của Instruments để thực hiện những test case phức tạp hay kiểm tra rò rỉ bộ nhớ (Memory leaking) trong quá trình chạy ứng dụng.
Ở phần tiếp theo, chúng ta sẽ tìm hiểu cách viết script trong Automation và các khái niệm, quy tắc lập trình trong của tập các Java Script API bên cạnh những tính năng của nó.
- Viết và sử dụng script trong Automation:
- Tạo Automation: B1: Khởi động ứng dụng Xcode:
B2: Khởi động Instruments từ Xcode (Một trong những công cụ được tích hợp cùng Xcode)
B3: Tạo Automation: Lựa chọn tạo một Automation từ Instruments
Kết quả: Sau khi khởi tạo ta sẽ nhận được một Automation:
Trong đó:
- Thiết bị và ứng dụng muốn kiểm thử: (Bao gồm cả device thật và Simulator)
- Editor để soạn thảo script: (Sử dụng ngôn ngữ Java Script)
- Các nút với chức năng ghi nhớ thao tác người dùng và thực thi script:
- Tạo Script:
B1: Vào mục Display Setting bên phải:
B2: Thêm mới script hoặc load từ file: (Import or Create)
Sử dụng Script: Sử dụng những Java Script API mà Apple cung cấp để thực hiện tương tác với UI trong ứng dụng ta đang phát triển.
Ghi nhớ lại những tương tác của người dùng, biến chúng thành script tương ứng: Ngoài việc tự viết ra những đoạn script để tương tác với UI của app, ta còn có thể ghi lại những tương tác của người sử dụng thông qua chức năng record của Automation như đã giới thiệu ở trên. Mỗi khi người dùng thực hiện một tương tác với UI thì Instruments sẽ tự động tạo ra đoạn script tương ứng. Ta có thể chèn, thêm, sửa xóa để được đoạn script như ý.
Truy cập và thao tác với các thành phần UI: Cấu trúc các thành phần UI trong ứng dụng: Các thành phần UI trong ứng dụng được tổ chức dưới dạng cây, chẳng hạn:
Trong đó class UIATarget chứa đối tượng gốc (root): localTarget là đối tượng đại diện cho thiết bị ta đang thực hiện trỏ tới để test. localTarget lại chứa đối tượng: frontMostApp - là đối tượng đại diện cho ứng dụng ta đang thực hiện trỏ tới để test. frontMostApp lại chứa đối tượng mainWindow - là màn hình hiện tại của ứng dụng (màn hình mà người sử dụng sẽ nhìn thấy ở thời điểm tương tác) mainWindow lại chứa từ 0 -> nhiều thành phần UI thành phần UI (Element UI) cũng có thể chứa 0 -> nhiều thành phần UI khác.
Do đó muốn tương tác với thành phần UI nào (button: nút , cell in table: một dòng trong một bảng,..) ta chỉ cần truy cập từ đối tượng gốc localTarget đi dần theo cấu trúc cây ở trên cho đến khi tìm được thành phần UI đó và thực hiện tương tác. (tap: chạm , double tap: 2 chạm, pinch: 2 chạm có kéo mở, swipe: vuốt,...)
Chẳng hạn với màn hình ứng dụng bên dưới:
thì các thành phần UI sẽ được tổ chức như sau:
Cách truy cập vào các thành phần UI trong ứng dụng: UIATarget.localTarget() : truy cập vào thiết bị hiện tại UIATarget.localTarget().frontMostApp() : truy cập vào ứng dụng cần test UIATarget.localTarget().frontMostApp().mainWindow() : truy cập vào màn hình hiện tại
UIATarget.localTarget().frontMostApp().mainWindow().elements(): truy cập vào tập các thành phần UI trên màn hình hiện tại UIATarget.localTarget().frontMostApp().mainWindow().tableViews() : truy cập vào tập các table trên màn hình hiện tại (các table trên màn hình hiện tại cũng sẽ nằm trong tập các thành phần UI, đây chỉ là một cách truy cập khác, cụ thể hơn với loại thành phần tương ứng) UIATarget.localTarget().frontMostApp().mainWindow().tabBar() : truy cập vào tabBar của ứng dụng (chẳng hạn trong ứng dụng bên trên)
Trên đây là cách thức truy cập vào các thành phần UI thông qua device -> ứng dụng -> màn hình hiện tại -> thành phần UI -> thành phần UI con -> thành phần UI cháu -> … -> thành phần UI cần tìm. (Trong trường hợp truy cập vào 1 tập các thành phần UI, chúng ta có thể triệu gọi chúng từ tập thu được thông qua trị số hoặc tên nhãn của chúng, chẳng hạn button: nút có tên nhãn là ”Edit” thì trong trị số của tập thu được ta điền vào ”Edit” -> truy cập được button tương ứng - UIATarget.localTarget().frontMostApp().mainWindow().buttons()[“Edit”]. Lưu ý: Cách thức dán nhãn tùy thuộc vào Developer)
Tương tác với các thành phần UI đã truy cập:
Với câu lệnh trên, Instruments sẽ thực hiện hành động tương đương với việc chạm vào button Edit trên màn hình ứng dụng.
Ghi log, xử lý các thông báo và capture màn hình:
Ghi log:
UIALogger.logStart("Logging element tree ...");Bắt đầu một đoạn log với tên Log
<element>.logElementTree(); Ghi ra danh sách toàn bộ những thành phần UI nằm trong thành phần UI: <element>
VD:UIATarget.localTarget().frontMostApp().mainWindow().tabBar().buttons()["Edit"],logElementTree(): ghi log toàn bộ thành phần UI nằm trong nút Edit
UIALogger.logMessage("Starting Module 001 branch 2, validating input."); Ghi ra một thông điệp vào Log
UIALogger.logPass(); *Kết thúc một đoạn log
VD: Với đoạn script sau, ta sẽ log một vài thông tin và capture màn hình*
Thông tin log thu được:
Xử lý thông báo:
Khi ứng dụng đưa ra 1 thông báo (alert). Instruments sẽ triệu gọi vào hàm onAlert như ta đã viết script bên dưới
UIATarget.onAlert = function onAlert(alert) { var title = alert.name(); Lấy tên của thông báo (Tiêu đề)
UIALogger.logWarning("Alert with title '" + title + "' encountered."); Ghi ra log từ thông tin trong thông báo
return false; Trả về false để đóng thông báo (tương đương với chọn nút No hay Cancel) và true để chấp nhận thông báo (tương đương với chọn nút OK hay chấp nhận)
Capture màn hình: UIATarget.localTarget().captureScreenWithName("TakeScreenShot"); Thực hiện chụp ảnh màn hình hiện tại và lưu dưới tên ”TakeScreenShot.png”