Espresso實戰:快速的Android UI自動化測試
在我和很多Android開發者聊天的時候,我注意到他們在開發的過程中并不注重測試這一環節,原因是他們認為Android測試太難實現,或者難以集成到現有的工程中等等。但是實際上寫一個 Espresso并不是一件很難的事情,而且它能夠非常方便地集成到你的工程之中。容易實現
Espresso測試是非常容易實現的,它由三部分組成:
- ViewMachers:尋找用來測試的View。
- ViewActions:發送交互事件。
- ViewAssertions:檢驗測試結果。 </ul>
舉個例子,接下來這部分代碼向id為name_field的EditText輸入”Steve”,并點擊id為greet_button的按鈕,最后檢查屏幕上是否有”Hello Steve!”字樣。
@Test
public void testSayHello() {
onView(withId(R.id.name_field)).perform(typeText("Steve"));
onView(withId(R.id.greet_button)).perform(click());
onView(withText("Hello Steve!")).check(matches(isDisplayed()));
}是不是很簡單?我們再來看看在多線程情況下如何進行測試。
集成測試Espresso官方文檔有這樣一段話:
引用
Espresso測試有個很強大的地方是它在多個測試操作中是線程安全的。Espresso會等待當前進程的消息隊列中的UI事件,并且在任何一個測試操作中會等待其中的AsyncTask結束才會執行下一個測試。這能夠解決程序中大部分的線程同步問題。
我一般使用 Retrofit來處理我的Http請求,而不是AsyncTask(雖然大多數人還是使用AsyncTask),在這種情況下也有別的辦法來實現線程安全的測試。Espresso中有個API叫做registerIdlingResource,它可以讓你使用自定義的線程安全邏輯。
通過IdlingResource,我們可以通過以下這段代碼來實現線程同步的Retrofit接口:
public class MockApiService implements ApiService, IdlingResource {
private final ApiService api;
private final AtomicInteger counter;
private final List<ResourceCallback> callbacks;
public MockApiService(ApiService api) {
this.api = api;
this.callbacks = new ArrayList<>();
this.counter = new AtomicInteger(0);
}
@Override
public Response doWork() {
counter.incrementAndGet();
return decrementAndNotify(api.doWork());
}
@Override
public String getName() {
return this.getClass().getName();
}
@Override
public boolean isIdleNow() {
return counter.get() == 0;
}
@Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
callbacks.add(resourceCallback);
}
private <T> T decrementAndNotify(T data) {
counter.decrementAndGet();
notifyIdle();
return data;
}
private void notifyIdle() {
if (counter.get() == 0) {
for (ResourceCallback cb : callbacks) {
cb.onTransitionToIdle();
}
}
}
}</pre>
這個類告訴了Espresso你的應用將會在(doWork())方法調用后才能夠進入下一個步驟。但是你看完這段代碼應該馬上意識到一件事情:這樣的寫法太過啰嗦了,你需要實現很多方法才能做到這線程同步一個小功能。一定有其他更好的辦法來實現(接下來就是了!)。
實際上技巧就隱藏在之前的官方文檔中,“Expresso會等待UI事件……并等待AsyncTask的結束才會執行下一個測試”。 實際上我們只要在AsyncTask的ThreadPoolExecutor中執行Retrofit請求就可以了!
幸運的是Retrofit的BaseAdapter.Builder類提供了這樣一種方法:
new RestAdapter.Builder()
.setExecutors(AsyncTask.THREAD_POOL_EXECUTOR, new MainThreadExecutor())
.build();
如此簡單,你還有理由不寫Espresso測試嗎?
本文出自: Michael Evans ,譯文出自: 開發技術前線 ,譯者: desmond1121 ,校對者: Mr.Simple