[譯] 使用 Espresso 隔離測試檢視

揚州慢發表於2017-05-02

使用 Espresso 隔離測試檢視

在這篇文章裡,我將會告訴你為何並且如何使用 Espresso 在 Android 裝置上測試你的自定義檢視。

你可以使用 Espresso 來一次性測試所有介面或流程。這些測試用例會啟動某個頁面,並像使用者一般執行操作,包括等待資料的載入或跳轉到其他頁面。

這樣做是非常有用的,因為你需要端到端的測試用例來驗證常見的使用者使用流程。這些自動化測試應該定期地執行,從而可以節約手工 QA 的時間來進行探索性測試。

即便如此,這些不是可以頻繁執行的測試。執行一整套可能會花費數小時的時間(想象一下驗證媒體內容的離線同步),所以你可以選擇在夜間執行它們。

這很困難,因為這些型別的測試包含了多個潛在的故障點。理想情況是,當某個測試失敗時,你會希望它是由於單個邏輯斷言而導致的。

大多數(或者說很多)可以引入的迴歸測試點都在 UI 上。這些問題很可能是十分細微的,以至於我們在新增新特性時並不會注意到,但是敏銳的 QA 團隊卻往往可以。

這樣就浪費太多時間了。

你能做些什麼?

讓我們來看下如何使用 Espresso 來測試正確地繫結了資料的檢視。

在 Novoda 裡,我們編寫的大多數檢視都是繼承自 Android 已有的 View 和 ViewGroup 類。這些檢視一般只會暴露了一到兩個方法用來繫結回撥函式和資料物件/檢視模型,如下所示:

public class MovieItemView extends RelativeLayout { 
private TextView titleTextView;
private Callback callback;
public void attach(Callback callback) {
this.callback = callback;

} public void bind(Movie movie) {
titleTextView.setText(movie.name());
setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) {
callback.onClick(movie);

}
});

}
}複製程式碼

他們將 UI 的邏輯部分組合在一起,並且通常還包含來自業務領域的命名規範。在
Novoda 的頁面佈局中你很少會看到“原始”的 Android 檢視。

讓我們使用 BDD 風格來編寫這些檢視測試,比如“當 MovieItemView 被繫結到 Edward Scissorhands 上,標題就被設定成 Edward Scissorhands”或者“MovieItemView 被繫結到 Edward Scissorhands 上,當點選檢視時,onClick(Edward Scissorhands) 就會被呼叫”,等等。(譯者注:BDD(Behaviour Driven Development),傾向於斷言被測物件的行為特徵而非輸入輸出。一個典型的 BDD 的測試用例包活完整的三段式上下文,測試大多可以翻譯為 Given-When-Then 的格式,即某種場景下,發生了事件,導致了什麼結果。)

難道不能使用單元測試來捕獲這些問題嗎?

如果你正在使用像 MVP 或者 MVVM 這樣可被單元測試的表現模式,為什麼還需要 Espresso 來執行這些測試呢?

首先,讓我們來看一下展示資訊的流程並且描述一下目前所能做的測試,然後再看看使用 Espresso 測試能多做些什麼。

  • Presenters 訂閱傳送事件的資料生成器

  • 事件可以處於載入中空閒錯誤狀態,並且可能帶有要展示的資料

  • Presenters 將使用 display(List<
    Movie>
    )
    displayCachedDataWhileLoading(List<
    Movie>
    )
    displayEmptyScreen() 等方法將這些事件轉發給“displayers”(MVP 中的“View”)。

  • displayers 的具體實現類將顯示/隱藏 Android 檢視,並執行諸如 moviesView.bind(List<
    Movie>
    )
    之類的操作

你可以對 presenters 進行單元測試,驗證是否呼叫了 displayers 正確的方法並且帶有正確的引數。

你可以用相同的方式測試 displayers 嗎?是的,你是可以模擬 Android 檢視,並驗證是否呼叫了正確的方法。但這樣的粒度並不是我們想要的:

  • displayer 可能確實構建或更新了 RecyclerView 或 ViewPager 介面卡,但這並不代表顯示了正確的內容。

  • Android 檢視是通過在程式碼中載入 XML(佈局和樣式)設定的;驗證方法的呼叫不足以斷言顯示的內容是否正確

設定測試用例

就從使用 espresso-support 這個庫開始吧。

在你的 build.gradle(JCenter 可用)裡新增依賴

debugCompile 'com.novoda:espresso-support-extras:0.0.3'  androidTestCompile 'com.novoda:espresso-support:0.0.3'複製程式碼

extras 依賴包中包含了 ViewActivity,在測試時需要將其新增到你的應用中。你可以在該 Activity 持有想要使用 Espresso 測試的單一檢視。

核心部分(包含自定義測試規則)只需要作為 androidTest 依賴中的一部分。

ViewTestRule 使用方法與 ActivityTestRule 類似。只不過是將傳遞的引數從想要啟動的 Activity 類替換成了包含你想要測試的檢視的佈局檔案:

@RunWith(AndroidJUnit4.class)publicclassMovieItemViewTest{ 
@Rule public ViewTestRule<
MovieItemView>
viewTestRule=newViewTestRule<
>
(R.layout.test_movie_item_view);
...複製程式碼

你可以使用 ViewTestRule<
MovieItemView>
指定根佈局的檢視型別。

ViewTestRule 繼承了 ActivityTestRule<
ViewActivity>
,所以它總會開啟 ViewActivitygetActivityIntent() 被重寫了,所以你可以將 R.layout.test_movie_item_view 作為 Intent 的附加資料傳遞給 ViewActivity

你可以在測試中使用 Mockito 代替回撥函式。

@Rulepublic MockitoRule mockitoRule = MockitoJUnit.rule();
@MockMovieItemView.Listener movieItemListener;
@BeforepublicvoidsetUp(){
MovieItemView view = viewTestRule.getView();
view.attachListener(movieItemListener);
...
}複製程式碼

ViewTestRule 有一個 bindViewUsing(Binder) 方法,該方法會返回檢視的引用,以便你與之進行互動。當你使用 viewTestRule.getView() 直接訪問檢視時,你會希望與檢視的所有互動都是在主執行緒上執行的,而非測試執行緒。

@Beforepublic void setUp() { 
MovieItemView view = viewTestRule.getView();
view.attachListener(movieItemListener);
viewTestRule.bindViewUsing(new ViewTestRule.Binder<
MovieItemView>
() {
@Override public void bind(MovieItemView view) {
view.bind(EDWARD_SCISSORHANDS);

}
});

}複製程式碼

準備測試

從使用者的角度上來看,應用其實只做了兩件事情:

  • 展示資訊

  • 響應使用者的操作

要為這兩種情況編寫測試,你可以先從使用標準的 Espresso ViewMatchers 和 ViewAssertions 語句斷言是否顯示正確的資訊開始:

@Testpublic void titleSetToMovieName() { 
onView(withId(R.id.movie_item_text_name)) .check(matches(withText(EDWARD_SCISSORHANDS.name)));

}複製程式碼

接著,你應該確保使用者的操作觸發了正確的點選事件,並且具有正確的引數:

@Testpublic void clickMovieItemView() { 
onView(withClassName(is(MovieItemView.class.getName()))) .perform(click());
verify(movieItemListener) .onClick(eq(EDWARD_SCISSORHANDS));

}複製程式碼

到這裡就完成了,希望這些知識對你有用。

在接下來的文章裡,我會介紹如何使用 Espresso 測試檢視時支援 TalkBack 服務(譯者注:Talkback 是一款由谷歌官方開發的系統工具軟體,它的定位是幫助盲人或者有視力障礙的使用者提供語言輔助)。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOSReact前端後端產品設計 等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃

來源:https://juejin.im/post/59088d650ce463006182a07a

相關文章