Dẫn nhập:

Trong giai đoạn này, mình được phân công viết UI Test bằng Calabash Android cho một dự án của DIV 3 và với bài viết này mình xin chia sẻ một vài mẹo và thủ thuật trong quá trình viết UI Test. Trước khi vào nội dung chính của bài viết này, các bạn nên tham khảo các bài viết với từ khóa “Calabash” trên Viblo để hiểu về định nghĩa, cách cài đặt môi trường, quy trình cũng như cách viết một scenario đơn giản. Ở đây mình sẽ không nhắc lại các kiến thức này để tránh bị trùng lặp nội dung không cần thiết.

Tips and Tricks

Mỗi Scenario là một đối tượng độc lập và có thể chạy riêng biệt mà không cần các scenario khác

Điều này là bắt buộc khi chúng ta viết các UI Test, sẽ ra sao nếu như một scenario fail khiến cho toàn bộ quá trình test phải dừng lại? Với dự án hiện tại, mình có cấu hình như sau với mỗi scenario để đảm bảo tính độc lập:

Before do |scenario|
    skip_this_scenario if scenario.source_tag_names.include? '@skip_scenario'
    reinstall_apps
    ensure_app_installed
    start_test_server_in_background
    end

    After('@last_scenario') do
    shutdown_test_server
    end

    After do |scenario|
    screenshot_embed if scenario.failed?
    end

=> Mỗi scenario đều được chạy sau khi app được cài mới và xóa toàn bộ data!

Khi code UI, nên đặt “id” cho các UI control

Việc đặt “id” khi code UI là điều thường hay làm đối với các bạn khi mới bắt đầu với Android, tuy nhiên càng về sau, thì chúng ta dần quên đi việc này, nhất là khi Android hỗ trợ “data binding” thì việc thêm “id” chỉ cần thiết trong một vài trường hợp, còn hầu hết là bị bỏ qua. Nếu UI của bạn cần Automation Test thì bạn nên đặt “id” đầy đủ cho các control. Mình xin đưa ra một ví dụ đơn giản như sau:

Scenario: I want to clicks an image on Welcome Screen
    Given I’m in Welcome Screen
    When I press view with id "abc"
Then

=> Trong trường hợp này, nếu image có "id" thì việc thao tác với image này sẽ dễ dàng hơn rất nhiều.

Hãy tận dụng các thuộc tính có sẵn của UI control để lưu trữ thông tin cần thiết

Trong trường hợp một UI control được dùng nhiều lần (ví dụ như add view bằng code), chúng ta không thể dựa vào “id” để phân biệt, lúc việc tận dụng các thuộc tính có sẵn để lưu trữ thông tin định danh control là một việc cần thiết. Chúng ta xét một ví dụ đơn giản như sau:

When /^I press the image "Test NPC #1"$/ do
    tap_when_element_exists("android.widget.ImageView id:'image_npc_talking' enabled:true contentDescription:'#{LAT_NPC_1} - #{LONG_NPC_1} - #{NAME_NPC_1}'")
end

=> Trong trường hợp này, trên Map Screen (sử sụng MapBox) sẽ có nhiều NPC (marker) sử dụng chung một UI, việc xác định từng NPC riêng biệt sẽ là một vấn đề lớn. Chúng ta sẽ tận dụng thuộc tính “contentDescription” để lưu trữ thông tin tên và tọa độ của NPC, việc này thực hiện dễ dàng trong logic code và không ảnh hưởng đến flow của app. Dựa trên thông tin của “contentDescription”, chúng ta có thể dễ dàng thao tác với từng NPC.

Calabash Android chỉ hỗ trợ Google Map v1

Dùng Calabash Android để làm Automation Test với các ứng dụng liên quan tới Map là một việc khó khăn và mất nhiều thời gian. Với app hiện tại của mình dùng MapBox thì chỉ dùng được tính năng duy nhất là “mock location”:

set_gps_coordinates(lat, long)

=> Tuy nhiên để có thể mock location, chúng ta cần “Allow mock location” trên device thật và ảo. Các bạn có thể xem hướng dẫn tại đâyđây

Sử dụng ScrollView một cách hợp lý

Với những UI có sử dụng ScrollView để chứa nhiều control, chúng ta có thể sử dụng và biến tấu các hàm có sẵn của Calabash để scroll view theo các hướng xác định theo ý muốn.

scroll_to("* marked:'#{label}'")

=> ScrollView sẽ dừng lại khi gặp label được định nghĩa.

loop do
        scroll('android.support.v4.widget.NestedScrollView', :down)
        break if element_exists("* marked:'#{label}'")
end

=> Scroll xuống đến khi nào gặp label (tương tự cho ScrollView, RecyclerView, ListView).

loop do
        scroll('android.widget.ScrollView', :down)
        break if element_exists("android.widget.CheckBox")
end

=> Scroll xuống đến khi nào gặp một control xác định (tương tự cho NếtdScrollView, RecyclerView, ListView).

i = 0
        loop do
        i += 500
        perform_action('drag_coordinates', 0, i, 0, 0)
        break if !query("android.widget.TextView {text CONTAINS '#{label}'}").empty?
end

=> Trong trường hợp UI có chứa nhiều ScrollView (liệt kê bằng lệnh query(“”)), chúng ta sẽ tiến hành scroll view theo hướng xác định dựa trên tọa độ x và y.

Please note that Calabash is no longer under active development

Đây là một điều đang tiếc, tuy nhiên với những tính năng hiện tại, chúng ta vẫn có thể áp dụng UI Automation Test bằng Calabash cho ứng dụng của mình. Trước khi tiến hành UI Test chúng nên nên lựa chọn phương pháp thích hợp nhất.

Kết

Hy vọng với những thông tin trong bài viết này sẽ giúp các bạn đang và sẽ làm UI Automation Test với Calabash có thêm những kinh nghiệm để hiện thực một cách nhanh chóng.