IdlingResource

閒置資源的力量在於不必等待應用程式的處理(網路,計算,動畫等)來完成 sleep(),這會帶來瑕疵和/或延長測試執行時間。官方文件可以在這裡找到。

履行

實現 IdlingResource 介面時,你需要做三件事:

  • getName() - 返回你的空閒資源的名稱。
  • isIdleNow() - 檢查你的 xyz 物件,操作等是否空閒。
  • registerIdleTransitionCallbackIdlingResource.ResourceCallback callback) - 提供一個回撥,當你的物件轉換為空閒時你應該呼叫它。

現在,你應該建立自己的邏輯並確定應用程式何時處於空閒狀態,何時處於空閒狀態,因為這取決於應用程式。下面你會看到一個簡單的例子,只是為了說明它是如何工作的。線上還有其他示例,但特定的應用程式實現會帶來特定的空閒資源實現。

筆記

  • 有一些谷歌的例子,他們把 IdlingResources 放在應用程式的程式碼中。**不要這樣做。**他們可能會把它放在那裡只是為了展示它們是如何工作的。
  • 保持程式碼清潔並保持單一的責任原則取決於你!

讓我們說你有一個奇怪的東西活動,並且需要花費很長時間才能載入片段,因此無法從片段中找到資源,從而使 Espresso 測試失敗(你應該更改活動的建立方式以及何時更改加快速度)。但無論如何要保持簡單,下面的例子展示了它應該是什麼樣子。

我們的示例空閒資源將獲得兩個物件:

  • 你需要查詢並等待附加到活動的片段的標記
  • 一個 FragmentManager 其用於查詢片段物件。
/**
 * FragmentIdlingResource - idling resource which waits while Fragment has not been loaded.
 */
public class FragmentIdlingResource implements IdlingResource {
    private final FragmentManager mFragmentManager;
    private final String mTag;
    //resource callback you use when your activity transitions to idle
    private volatile ResourceCallback resourceCallback;

    public FragmentIdlingResource(FragmentManager fragmentManager, String tag) {
        mFragmentManager = fragmentManager;
        mTag = tag;
    }

    @Override
    public String getName() {
        return FragmentIdlingResource.class.getName() + ":" + mTag;
    }

    @Override
    public boolean isIdleNow() {
        //simple check, if your fragment is added, then your app has became idle
        boolean idle = (mFragmentManager.findFragmentByTag(mTag) != null);
        if (idle) {
            //IMPORTANT: make sure you call onTransitionToIdle
            resourceCallback.onTransitionToIdle();
        }
        return idle;
    }

    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        this.resourceCallback = resourceCallback;
    }
}

現在你已經編寫了 IdlingResource,你需要在某處使用它嗎?

用法

讓我們跳過整個測試類設定,看看測試用例的外觀如何:

@Test
public void testSomeFragmentText() {
    mActivityTestRule.launchActivity(null);
   
    //creating the idling resource
    IdlingResource fragmentLoadedIdlingResource = new FragmentIdlingResource(mActivityTestRule.getActivity().getSupportFragmentManager(), SomeFragmentText.TAG);
    //registering the idling resource so espresso waits for it
    Espresso.registerIdlingResources(idlingResource1);
    onView(withId(R.id.txtHelloWorld)).check(matches(withText(helloWorldText)));

    //lets cleanup after ourselves
    Espresso.unregisterIdlingResources(fragmentLoadedIdlingResource);
}

結合 JUnit 規則

這不難; 你還可以以 JUnit 測試規則的形式應用空閒資源。例如,假設你有一些包含 Volley 的 SDK,並且你希望 Espresso 等待它。你可以建立一個 JUnit 規則,而不是遍歷每個測試用例或在設定中應用它,而只需編寫:

@Rule
public final SDKIdlingRule mSdkIdlingRule = new SDKIdlingRule(SDKInstanceHolder.getInstance());

既然這是一個例子,不要把它視為理所當然; 這裡的所有程式碼都是虛構的,僅用於演示目的:

public class SDKIdlingRule implements TestRule {
    //idling resource you wrote to check is volley idle or not
    private VolleyIdlingResource mVolleyIdlingResource;
    //request queue that you need from volley to give it to idling resource
    private RequestQueue mRequestQueue;

    //when using the rule extract the request queue from your SDK
    public SDKIdlingRule(SDKClass sdkClass) {
        mRequestQueue = getVolleyRequestQueue(sdkClass);
    }

    private RequestQueue getVolleyRequestQueue(SDKClass sdkClass) {
        return sdkClass.getVolleyRequestQueue();
    }

    @Override
    public Statement apply(final Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                //registering idling resource
                mVolleyIdlingResource = new VolleyIdlingResource(mRequestQueue);
                Espresso.registerIdlingResources(mVolleyIdlingResource);
                try {
                    base.evaluate();
                } finally {
                    if (mVolleyIdlingResource != null) {
                        //deregister the resource when test finishes
                        Espresso.unregisterIdlingResources(mVolleyIdlingResource);
                    }
                }
            }
        };
    }
}