之前介绍的都是逻辑测试,不用运行在模拟器或者真机上,做Android开发测试,免不了要进行UI测试,而大部分的UI更新都是异步的,这时候要进行单元测试就需要想别的方法了。这里介绍一下框架,espresso,体积小,运行快。
对同步更新UI的方法进行测试并不难,比如点击按钮,点击后改变Textview
的内容,这很简单。但是更多时候我们用到的是异步更新UI。如果直接进行测试,大概率会报错,因为在执行测试代码来测试数据是否展示在UI上时,异步数据很有可能还没有获取到。针对这个问题,我们借助espresso,使用框架中的SimpleCountingIdlingResource
和EspressoIdlingResourceManager
可以实现异步更新UI的测试。
- 首先在activity中添加这样一个方法,这个方法是给测试时提供获取IdlingResource的接口
@VisibleForTesting
public SimpleCountingIdlingResource getCountingIdlingResource() {
return EspressoIdlingResourceManager.getIdlingResource();
}
- 当我们开始异步请求前,将IdlingResource的标记加一,这就意味着已经开始异步了
//在开始异步请求前添加这行代码,意味着开始了异步
EspressoIdlingResourceManager.increment();
当请求结束,我们再添加这行代码,说明网络请求结束:
//异步加载成功,结束异步
if (!EspressoIdlingResourceManager.getIdlingResource().isIdleNow()) {
EspressoIdlingResourceManager.decrement();
}
然后回到测试类中,添加如下测试代码:
private IdlingResource idlingresource;
@Test
public void testAsync2() throws Exception {
//调用Activity中我们已经设置好的getIdlingresource()方法,获取Idlingresource对象
idlingresource = ((MainActivity) activityTestRule.getActivity()).getCountingIdlingResource();
// 操作:点击Button
onView(withId(R.id.async_btn))
.perform(click());
//注册异步监听,当该idlingresource中的counter标记值为0时才进行接下来的测试代码
Espresso.registerIdlingResources(idlingresource);
// 未注册idlingResource时,立即进行test,此时异步并未结束,报错(tests failed)
onView(withId(R.id.textview))
.check(matches(withText("异步测试结果显示")))
.check(matches(isDisplayed()));
//我们在测试结束后取消注册,释放资源
Espresso.unregisterIdlingResources(idlingresource);
}
上面提到了两个类的源码如下:
EspressoIdlingResourceManager.class
public class EspressoIdlingResourceManager {
private static final String RESOURCE = "GLOBAL";
private static SimpleCountingIdlingResource mCountingIdlingResource =
new SimpleCountingIdlingResource(RESOURCE);
public static void increment() {
mCountingIdlingResource.increment();
}
public static void decrement() {
mCountingIdlingResource.decrement();
}
public static SimpleCountingIdlingResource getIdlingResource() {
return mCountingIdlingResource;
}
}
SimpleCountingIdlingResource.class
public final class SimpleCountingIdlingResource implements IdlingResource {
private final String mResourceName;
//这个counter值就像一个标记,默认为0
private final AtomicInteger counter = new AtomicInteger(0);
private volatile ResourceCallback resourceCallback;
public SimpleCountingIdlingResource(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;
}
//每当我们开始异步请求,把counter值+1
public void increment() {
counter.getAndIncrement();
}
//当我们获取到网络数据后,counter值-1;
public void decrement() {
int counterVal = counter.decrementAndGet();
//如果这时counter == 0,说明异步结束,执行回调。
if (counterVal == 0) {
//
if (null != resourceCallback) {
resourceCallback.onTransitionToIdle();
}
}
if (counterVal < 0) {
//如果小于0,抛出异常
throw new IllegalArgumentException("Counter has been corrupted!");
}
}
}
这样,我们就完成了异步更新UI的测试。