IdlingResource
闲置资源的力量在于不必等待应用程序的处理(网络,计算,动画等)来完成 sleep()
,这会带来瑕疵和/或延长测试运行时间。官方文档可以在这里找到。
履行
实现 IdlingResource
接口时,你需要做三件事:
getName()
- 返回你的空闲资源的名称。isIdleNow()
- 检查你的 xyz 对象,操作等是否空闲。registerIdleTransitionCallback
(IdlingResource.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);
}
}
}
};
}
}