Tài liệu này giải thích cách hoàn tất các thao tác kiểm thử tự động phổ biến bằng cách sử dụng API Espresso.
Espresso API khuyến khích tác giả kiểm thử suy nghĩ về những gì mà người dùng có thể
thực hiện trong khi tương tác với ứng dụng – xác định vị trí các phần tử trên giao diện người dùng và tương tác
với họ. Đồng thời, khung này cũng ngăn chặn quyền truy cập trực tiếp vào các hoạt động
và lượt xem của ứng dụng do giữ các đối tượng này và
trên chúng, ngoài luồng giao diện người dùng là một nguyên nhân chính gây ra tình trạng không ổn định. Do đó, bạn sẽ
không thấy các phương thức như getView()
và getCurrentActivity()
trong API Espresso.
Bạn vẫn có thể vận hành an toàn trên các khung hiển thị bằng cách triển khai các lớp con của riêng bạn
ViewAction
và ViewAssertion
.
Thành phần API
Các thành phần chính của Espresso bao gồm:
- Espresso – Điểm truy cập đến hoạt động tương tác với khung hiển thị (thông qua
onView()
vàonData()
). Đồng thời hiển thị các API không nhất thiết phải liên kết với bất kỳ khung hiển thị nào, chẳng hạn như dưới tênpressBack()
. - ViewMatchers – Một tập hợp các đối tượng triển khai phương thức
Giao diện
Matcher<? super View>
. Bạn có thể truyền một hoặc nhiều mã này vào Phương thứconView()
để xác định một khung hiển thị trong hệ phân cấp khung hiển thị hiện tại. - ViewActions – Một tập hợp các đối tượng
ViewAction
có thể được truyền đến phương thứcViewInteraction.perform()
, chẳng hạn nhưclick()
. - ViewAssertion – Một tập hợp các đối tượng
ViewAssertion
có thể được đã truyền phương thứcViewInteraction.check()
. Trong mọi trường hợp, bạn sẽ sử dụng khớp với câu nhận định, sử dụng trình so khớp Khung hiển thị để xác nhận trạng thái của chế độ xem hiện được chọn.
Ví dụ:
Kotlin
// withId(R.id.my_view) is a ViewMatcher // click() is a ViewAction // matches(isDisplayed()) is a ViewAssertion onView(withId(R.id.my_view)) .perform(click()) .check(matches(isDisplayed()))
Java
// withId(R.id.my_view) is a ViewMatcher // click() is a ViewAction // matches(isDisplayed()) is a ViewAssertion onView(withId(R.id.my_view)) .perform(click()) .check(matches(isDisplayed()));
Tìm một chế độ xem
Trong hầu hết các trường hợp, phương thức onView()
sẽ sử dụng trình so khớp hamcrest
dự kiến sẽ khớp với một và chỉ một chế độ xem trong chế độ xem hiện tại
thứ bậc. Trình so khớp là một công cụ hữu ích và quen thuộc với những ai đã từng sử dụng
bằng Mockito hoặc JUnit. Nếu bạn chưa biết nhiều về công cụ so khớp hamcrest, chúng tôi
bạn nên bắt đầu bằng việc xem nhanh thông tin này
bản trình bày.
Thông thường, thành phần hiển thị mong muốn có một R.id
duy nhất và một trình so khớp withId
đơn giản sẽ
thu hẹp tìm kiếm chế độ xem. Tuy nhiên, có nhiều trường hợp hợp pháp khi bạn
không thể xác định R.id
tại thời điểm phát triển kiểm thử. Ví dụ: chế độ xem cụ thể
có thể không có R.id
hoặc R.id
không phải là duy nhất. Điều này có thể làm cho bình thường
cho phép kiểm thử đo lường rất khó viết và phức tạp vì đây là cách thông thường để
thì quyền truy cập vào khung hiển thị này (bằng findViewById()
) không hoạt động. Do đó, bạn có thể
cần truy cập vào các thành viên riêng tư của Hoạt động hoặc Mảnh chứa chế độ xem hoặc
hãy tìm một vùng chứa có R.id
đã biết rồi chuyển đến nội dung của vùng chứa đó
chế độ xem cụ thể.
Espresso xử lý vấn đề này dễ dàng bằng cách cho phép bạn thu hẹp khung hiển thị
bằng cách sử dụng đối tượng ViewMatcher
hiện có hoặc đối tượng tuỳ chỉnh của riêng bạn.
Bạn có thể tìm một thành phần hiển thị theo R.id
bằng cách gọi onView()
:
Kotlin
onView(withId(R.id.my_view))
Java
onView(withId(R.id.my_view));
Đôi khi, các giá trị R.id
được dùng chung giữa nhiều chế độ xem. Khi điều này xảy ra,
việc cố gắng sử dụng một R.id
cụ thể sẽ mang lại cho bạn một ngoại lệ, chẳng hạn như
AmbiguousViewMatcherException
. Thông báo trường hợp ngoại lệ sẽ cung cấp cho bạn một văn bản
bản trình bày của hệ phân cấp khung hiển thị hiện tại mà bạn có thể tìm kiếm và tìm thấy
các khung hiển thị khớp với R.id
không phải là duy nhất:
java.lang.RuntimeException: androidx.test.espresso.AmbiguousViewMatcherException This matcher matches multiple views in the hierarchy: (withId: is <123456789>) ... +----->SomeView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true, is-focused=false, is-focusable=false, enabled=true, selected=false, is-layout-requested=false, text=, root-is-layout-requested=false, x=0.0, y=625.0, child-count=1} ****MATCHES**** | +------>OtherView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true, is-focused=false, is-focusable=true, enabled=true, selected=false, is-layout-requested=false, text=Hello!, root-is-layout-requested=false, x=0.0, y=0.0, child-count=1} ****MATCHES****
Khi xem qua các thuộc tính khác nhau của khung hiển thị, bạn có thể thấy
các thuộc tính có thể nhận dạng. Trong ví dụ trên, một trong các khung hiển thị có văn bản
"Hello!"
. Bạn có thể sử dụng tuỳ chọn này để thu hẹp tìm kiếm của mình bằng cách sử dụng tổ hợp
trình so khớp:
Kotlin
onView(allOf(withId(R.id.my_view), withText("Hello!")))
Java
onView(allOf(withId(R.id.my_view), withText("Hello!")));
Bạn cũng có thể chọn không đảo ngược bất kỳ trình so khớp nào:
Kotlin
onView(allOf(withId(R.id.my_view), not(withText("Unwanted"))))
Java
onView(allOf(withId(R.id.my_view), not(withText("Unwanted"))));
Xem ViewMatchers
cho trình so khớp khung hiển thị do Espresso cung cấp.
Những yếu tố nên cân nhắc
- Trong một ứng dụng hoạt động tốt, tất cả khung hiển thị mà người dùng có thể tương tác
phải chứa văn bản mô tả hoặc có mô tả nội dung. Xem
Tăng khả năng hỗ trợ tiếp cận của ứng dụng cho nhiều người dùng hơn
chi tiết. Nếu bạn không thể thu hẹp nội dung tìm kiếm bằng
withText()
hoặcwithContentDescription()
, hãy xem xét việc này là một lỗi hỗ trợ tiếp cận. - Sử dụng trình so khớp ít mô tả nhất tìm được chế độ xem bạn đang tìm kiếm
cho. Đừng chỉ định quá mức vì điều này sẽ buộc khung phải làm nhiều việc hơn
là cần thiết. Ví dụ: nếu có thể nhận dạng chính xác một khung hiển thị bằng văn bản, thì bạn
không cần chỉ định thành phần hiển thị cũng có thể gán từ
TextView
. Đối với nhiềuR.id
của khung hiển thị là đủ. - Nếu thành phần hiển thị đích nằm trong
AdapterView
(chẳng hạn nhưListView
),GridView
hoặcSpinner
– phương thứconView()
có thể không hoạt động. Trong các trường hợp, bạn nên sử dụngonData()
.
Thực hiện thao tác trên một khung hiển thị
Sau khi tìm được trình so khớp phù hợp cho khung hiển thị mục tiêu, bạn có thể
thực hiện các bản sao của ViewAction
trên đó bằng phương thức perform.
Ví dụ: để nhấp vào chế độ xem, hãy làm như sau:
Kotlin
onView(...).perform(click())
Java
onView(...).perform(click());
Bạn có thể thực thi nhiều thao tác bằng một lệnh gọi thực hiện:
Kotlin
onView(...).perform(typeText("Hello"), click())
Java
onView(...).perform(typeText("Hello"), click());
Nếu thành phần hiển thị bạn đang xử lý nằm bên trong một ScrollView
(dọc hoặc
ngang), hãy xem xét các hành động trước đó yêu cầu khung hiển thị
được hiển thị (chẳng hạn như click()
và typeText()
) cùng với scrollTo()
. Chiến dịch này
giúp đảm bảo khung hiển thị sẽ hiện trước khi tiếp tục thao tác khác:
Kotlin
onView(...).perform(scrollTo(), click())
Java
onView(...).perform(scrollTo(), click());
Xem ViewActions
cho các thao tác đối với thành phần hiển thị do Espresso cung cấp.
Kiểm tra xác nhận lượt xem
Bạn có thể áp dụng câu nhận định cho khung hiển thị hiện được chọn bằng check()
. Đối tượng xác nhận được sử dụng nhiều nhất là lời khẳng định matches()
. Chiến dịch này sử dụng một
Đối tượng ViewMatcher
để xác nhận trạng thái của khung hiển thị hiện được chọn.
Ví dụ: để kiểm tra nhằm đảm bảo rằng một thành phần hiển thị có văn bản "Hello!"
:
Kotlin
onView(...).check(matches(withText("Hello!")))
Java
onView(...).check(matches(withText("Hello!")));
Nếu bạn muốn xác nhận rằng "Hello!"
là nội dung của thành phần hiển thị, thì những trường hợp sau đây được coi là phương pháp không hợp lệ:
Kotlin
// Don't use assertions like withText inside onView. onView(allOf(withId(...), withText("Hello!"))).check(matches(isDisplayed()))
Java
// Don't use assertions like withText inside onView. onView(allOf(withId(...), withText("Hello!"))).check(matches(isDisplayed()));
Mặt khác, nếu bạn muốn xác nhận rằng một thành phần hiển thị có văn bản "Hello!"
là
hiển thị (ví dụ: sau khi thay đổi cờ chế độ hiển thị),
mã tốt.
Xem kiểm thử đơn giản về câu nhận định
Trong ví dụ này, SimpleActivity
chứa Button
và TextView
. Khi
nút được nhấp vào, nội dung của TextView
sẽ thay đổi thành "Hello Espresso!"
.
Sau đây là cách kiểm thử bằng Espresso:
Nhấp vào nút
Bước đầu tiên là tìm một thuộc tính giúp tìm thấy nút đó. Chiến lược phát hành đĩa đơn
nút trong SimpleActivity
có một R.id
duy nhất, đúng như dự kiến.
Kotlin
onView(withId(R.id.button_simple))
Java
onView(withId(R.id.button_simple));
Bây giờ, để thực hiện nhấp chuột:
Kotlin
onView(withId(R.id.button_simple)).perform(click())
Java
onView(withId(R.id.button_simple)).perform(click());
Xác minh văn bản TextView
TextView
kèm theo văn bản cần xác minh cũng có một R.id
duy nhất:
Kotlin
onView(withId(R.id.text_simple))
Java
onView(withId(R.id.text_simple));
Bây giờ, hãy xác minh văn bản nội dung:
Kotlin
onView(withId(R.id.text_simple)).check(matches(withText("Hello Espresso!")))
Java
onView(withId(R.id.text_simple)).check(matches(withText("Hello Espresso!")));
Kiểm tra quá trình tải dữ liệu trong chế độ xem bộ chuyển đổi
AdapterView
là một loại tiện ích đặc biệt có thể tự động tải dữ liệu từ
một Bộ chuyển đổi. Ví dụ phổ biến nhất về AdapterView
là ListView
. Như
trái ngược với các tiện ích tĩnh như LinearLayout
, đây chỉ là một tập hợp con của
Bạn có thể tải AdapterView
thành phần con vào hệ phân cấp khung hiển thị hiện tại. Một đơn giản
Tìm kiếm onView()
sẽ không tìm thấy các chế độ xem hiện chưa được tải.
Espresso xử lý việc này bằng cách cung cấp một điểm truy cập onData()
riêng biệt
trước tiên có thể tải mục bộ chuyển đổi được đề cập, đưa mục đó vào tiêu điểm trước khi
thao tác trên nó hoặc bất kỳ phần tử con nào của nó.
Cảnh báo: Các cách triển khai tuỳ chỉnh của
AdapterView
có thể gặp sự cố với onData()
nếu chúng phá vỡ hợp đồng thừa kế, đặc biệt là
API getItem()
. Trong những trường hợp như vậy, phương án hành động tốt nhất là
tái cấu trúc mã xử lý ứng dụng. Nếu không thể làm như vậy, bạn có thể triển khai một
khớp với AdapterViewProtocol
tuỳ chỉnh. Để biết thêm thông tin, hãy tham khảo
xem mục mặc định
Lớp AdapterViewProtocols
do Espresso cung cấp.
Kiểm thử đơn giản chế độ xem bộ chuyển đổi
Chương trình kiểm thử đơn giản này minh hoạ cách sử dụng onData()
. SimpleActivity
có chứa
Spinner
với một vài mặt hàng đại diện cho các loại cà phê. Khi một
mục được chọn, có TextView
thay đổi thành "One %s a day!"
, trong đó
%s
thể hiện mục đã chọn.
Mục tiêu của quy trình kiểm thử này là mở Spinner
, chọn một mục cụ thể và
xác minh rằng TextView
chứa mục đó. Vì lớp Spinner
dựa trên
vàoAdapterView
, bạn nên sử dụng onData()
thay vì onView()
cho
khớp với mục.
Mở phần lựa chọn mặt hàng
Kotlin
onView(withId(R.id.spinner_simple)).perform(click())
Java
onView(withId(R.id.spinner_simple)).perform(click());
Hãy chọn một mục
Đối với phần lựa chọn mục, Spinner
sẽ tạo một ListView
với nội dung tương ứng.
Chế độ xem này có thể rất dài và thành phần có thể không được đóng góp cho chế độ xem
thứ bậc. Bằng cách sử dụng onData()
, chúng ta buộc phần tử mong muốn vào khung hiển thị
thứ bậc. Các mục trong Spinner
là chuỗi nên chúng ta muốn so khớp một mục
bằng Chuỗi "Americano"
:
Kotlin
onData(allOf(`is`(instanceOf(String::class.java)), `is`("Americano"))).perform(click())
Java
onData(allOf(is(instanceOf(String.class)), is("Americano"))).perform(click());
Xác minh rằng nội dung trong văn bản là chính xác
Kotlin
onView(withId(R.id.spinnertext_simple)) .check(matches(withText(containsString("Americano"))))
Java
onView(withId(R.id.spinnertext_simple)) .check(matches(withText(containsString("Americano"))));
Gỡ lỗi
Espresso cung cấp thông tin gỡ lỗi hữu ích khi kiểm thử không thành công:
Ghi nhật ký
Espresso ghi lại tất cả các thao tác xem vào logcat. Ví dụ:
ViewInteraction: Performing 'single click' action on view with text: Espresso
Hệ phân cấp chế độ xem
Espresso in hệ phân cấp khung hiển thị trong thông báo ngoại lệ khi onView()
không thành công.
- Nếu
onView()
không tìm thấy khung hiển thị đích, thìNoMatchingViewException
sẽ là gửi. Bạn có thể kiểm tra hệ phân cấp khung hiển thị trong chuỗi ngoại lệ để phân tích lý do khiến trình so khớp không khớp với bất kỳ chế độ xem nào. - Nếu
onView()
tìm thấy nhiều khung hiển thị khớp với trình so khớp đã cho, thì Hệ thống sẽ gửiAmbiguousViewMatcherException
. Hệ phân cấp khung hiển thị được in và tất cả các chế độ xem đã khớp sẽ được đánh dấu bằng nhãnMATCHES
:
java.lang.RuntimeException: androidx.test.espresso.AmbiguousViewMatcherException This matcher matches multiple views in the hierarchy: (withId: is <123456789>) ... +----->SomeView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true, is-focused=false, is-focusable=false, enabled=true, selected=false, is-layout-requested=false, text=, root-is-layout-requested=false, x=0.0, y=625.0, child-count=1} ****MATCHES**** | +------>OtherView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true, is-focused=false, is-focusable=true, enabled=true, selected=false, is-layout-requested=false, text=Hello!, root-is-layout-requested=false, x=0.0, y=0.0, child-count=1} ****MATCHES****
Khi xử lý hệ phân cấp khung hiển thị phức tạp hoặc hành vi không mong muốn của tiện ích việc sử dụng Trình xem phân cấp trong Android Studio dành cho một lời giải thích.
Cảnh báo về chế độ xem bộ chuyển đổi
Espresso cảnh báo người dùng về sự hiện diện của tiện ích AdapterView
. Khi một onView()
sẽ gửi một tiện ích NoMatchingViewException
và AdapterView
có trong hệ phân cấp khung hiển thị, giải pháp phổ biến nhất là sử dụng onData()
.
Thông báo ngoại lệ sẽ bao gồm một cảnh báo kèm theo danh sách các chế độ xem bộ chuyển đổi.
Bạn có thể dùng thông tin này để gọi onData()
nhằm tải khung hiển thị mục tiêu.
Tài nguyên khác
Để biết thêm thông tin về cách sử dụng Espresso trong quy trình kiểm thử Android, hãy tham khảo các tài nguyên sau đây.
Mẫu
- CustomMatcherSample (Mẫu tuỳ chỉnh):
Cho biết cách mở rộng Espresso để khớp với thuộc tính gợi ý của đối tượng
EditText
. - RecyclerViewMẫu:
Các thao tác
RecyclerView
cho Espresso. - (xem thêm...)