Android自動化測試是應用開發中提升開發效率的一種方式,它可以在短時間內跑完所有的測試方案以及實現各種交互,從而讓開發者更加方便和直觀的知道代碼的實現效果。Android自動化測試可以分為單元測試、UI測試、Monkey測試三種,同時也分小中大三種測試。
單元測試又稱為模塊測試, 是針對程序模塊(軟體設計的最小單位)來進行正確性檢驗的測試工作。程序單元是應用的最小可測試部件。Android中的單元測試是基於JUnit,可分為本地測試和Instrumented 測試。
單元測試最常用的框架就是JUnit跟Mockito組合的測試框架,其中JUnit用來跑主要的測試代碼,Mockito可以創建特定測試對象(非對象本身)並設置一些特定的屬性供測試使用。
UI測試是測試應用中的各種交互是否達到了實現的效果。常用的UI測試框架有Espresso和UIAutomator。
Espresso有三個重要的類:分別是Matchers(匹配器),ViewAction(界面行為),ViewAssertions(界面判斷),其中Matchers是常常是通過匹配條件來需找UI組件或過濾UI,而ViewAction是來模擬用戶操作界面的行為,ViewAssertions對模擬行為操作的View進行變換和結果驗證。它的執行順序如下:
在導入好包之後就可以module的AndroidTest包下開始編寫自己的UI自動化測試代碼了。
測試界面跳轉時需要用的Espresso-Intents庫,它是 Espresso 的擴展程序,支持對被測應用發出的intent進行驗證和打樁。它與Mockit 類似,但適用於Android Intent。Espresso-Intents有兩個比較重要的方法itending()和intended()。
@Test fun validateIntentSentToPackage() { user.clickOnView(system.getView(R.id.callButton)) intended(toPackage("com.android.phone")) }Espresso測試有個很強大之處就是它在多個測試操作中是線程安全的,它會等待當前進程的消息隊列中的UI事件,並且在任何一個測試操作中會等待其中的異步任務結束才會執行下一個測試。
Espresso異步測試是要導入以下兩個包:
下面講一下異步測試的流程:
新建一個類繼承IdlingResource
public class SimpleIdlingResource implements IdlingResource { private final String mResourceName;
private final AtomicInteger counter = new AtomicInteger(0);
private volatile ResourceCallback resourceCallback;
public SimpleIdlingResource(String resourceName) { mResourceName = resourceName; }
@Override public String getName() { return mResourceName; }
@Override public boolean isIdleNow() { return counter.get() == 0; }
@Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { this.resourceCallback = resourceCallback; }
public void increment() { counter.getAndIncrement(); }
public void decrement() { int counterVal = counter.decrementAndGet(); if (counterVal == 0) { if (null != resourceCallback) { resourceCallback.onTransitionToIdle(); } }
if (counterVal < 0) { throw new IllegalArgumentException("Counter has been corrupted!"); } }}新建一個管理類去管理上述類
public class EspressoIdlingResource { private static final String RESOURCE = "GLOBAL";
private static SimpleIdlingResource mCountingIdlingResource = new SimpleIdlingResource(RESOURCE);
public static void increment() { mCountingIdlingResource.increment(); }
public static void decrement() { mCountingIdlingResource.decrement(); }
public static IdlingResource getIdlingResource() { return mCountingIdlingResource; }}將管理類插入到異步代碼中
在異步任務開始前插入代碼
protected void onReqStart(int where) { EspressoIdlingResource.increment(); }異步任務結束後插入代碼
private void onFinish() { if(!EspressoIdlingResource.getIdlingResource().isIdleNow()){ EspressoIdlingResource.decrement(); } }在測試代碼中註冊IdlingRecource
@Before public void setUp() throws Exception { idlingresource = activityRule.getActivity().getIdlingresource();
Espresso.registerIdlingResources(idlingresource); }
@Test public void onLoadingFinished() throws Exception {
onView(withId(R.id.text)) .check(matches(withText("success!"))); }
@After public void release() throws Exception { Espresso.unregisterIdlingResources(idlingresource); }ViewAction()中的typeText()使用。
如果直接調用typeText(),那麼它的使用對象就一定是editText,如果是自定義的未繼承editText的view使用typeText()時,要在使用前supportsInputMethods(),否則會報錯誤。
onView(allOf(supportsInputMethods(), isDescendantOfA(withId(R.id.test)))).perform(typeText("111111"))在調用完typeText()後最好調用一下 closeSoftKeyboard(),否則會出現某些view在點擊時被阻擋而報錯。
自動化測試的目的不僅僅是解放雙手,它也可以讓開發者提前知道某些小bug,不用到了測試階段才被提出來,這樣就提升了開發的效率。