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