的Android RecyclerView适配器个计数单元测试
我试图用AndroidJunit4测试RecyclerView返回0,这是我的测试代码:的Android RecyclerView适配器个计数单元测试
@Rule
public ActivityTestRule<ProductListActivity> rule = new ActivityTestRule<>(ProductListActivity.class);
............................
..........................
@Test
public void ensureDataIsLoadingOnSuccess() throws Exception {
ProductListActivity activity = rule.getActivity();
...........................
............
activity.runOnUiThread(new Runnable() {
public void run() {
activity.displayProducts(asList(product1, product2), 0);
}
});
assertEquals(2, mAdapter.getItemCount());
assertThat(((ProductAdapter) mAdapter).getItemAtPosition(0),sameInstance(product1));
assertThat(((ProductAdapter) mAdapter).getItemAtPosition(1),sameInstance(product2));
}
这是在练习我的displayProducts代码():
@Override
public void displayProducts(List<Product> products, Integer pageNo) {
progressBar.setVisibility(View.GONE);
if (pageNo == 0 && products.size() == 0) {
noProductTextView.setVisibility(View.VISIBLE);
} else {
mProductAdapter.addProduct(products);
noProductTextView.setVisibility(View.GONE);
productListView.setVisibility(View.VISIBLE);
}
}
这是给错误,如:
junit.framework.AssertionFailedError: expected:<2> but was:<0>
at junit.framework.Assert.fail(Assert.java:50)
at junit.framework.Assert.failNotEquals(Assert.java:287)
at junit.framework.Assert.assertEquals(Assert.java:67)
at junit.framework.Assert.assertEquals(Assert.java:199)
at junit.framework.Assert.assertEquals(Assert.java:205)
at com.kaushik.myredmart.ui.ProductListActivityTest.ensureDataIsLoadingOnSuccess(ProductListActivityTest.java:94)
请帮助什么是我的代码的问题?
我在这里可以看到一个问题,在Main/UI线程能够更新它之前,您正在查询列表大小。所以,你将不得不在当前线程中等待Activity完成更新主线程列表。
你可以做,
Thread.sleep(500);
在测试类等
,以测试在活动列表中设置的行为,你会发现断言是有效的。
由于主线程运行无限,直到应用程序运行,您将不得不实现由Activity提供的回调接口,以通知填充列表何时完成。
问题是为什么Espresso不会等到'MessageQueue'为空? – azizbekian
@azizbekian,因为它在另一个线程(背景)上运行。 添加一个观察者设计模式,并将其捕获到确切的时间,否则使用线程休眠方法。 –
您的说明不正确:Espresso在后台线程上运行**,但是**它将UI线程的MessageQueue侦听为空,并且只有在Espresso将继续使用匹配器时它才为空。您提出了一个解决方法,但不能说明问题出现的原因。 – azizbekian
原因是您的Espresso测试没有等待您的加载任务,这是非常耗时的。 您需要使用espresso-idling-resource
来指示它等待此任务完成。
然后,您需要一个类来实现IdlingResource
并将其声明为您的活动。
当您的Espresso测试运行时,它会知道并等待您长时间消耗的任务来完成并测试结果。
首先,添加它的依赖关系。其次,你需要在src/main/java/your-package文件夹中有两个Java文件。
SimpleCountingIdlingResource.java
public final class SimpleCountingIdlingResource implements IdlingResource {
private final String mResourceName;
private final AtomicInteger counter = new AtomicInteger(0);
// written from main thread, read from any thread.
private volatile ResourceCallback resourceCallback;
/**
* Creates a SimpleCountingIdlingResource
*
* @param resourceName the resource name this resource should report to Espresso.
*/
public SimpleCountingIdlingResource(String resourceName) {
mResourceName = checkNotNull(resourceName);
}
@Override public String getName() {
return mResourceName;
}
@Override public boolean isIdleNow() {
return counter.get() == 0;
}
@Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
this.resourceCallback = resourceCallback;
}
/**
* Increments the count of in-flight transactions to the resource being monitored.
*/
public void increment() {
counter.getAndIncrement();
}
/**
* Decrements the count of in-flight transactions to the resource being monitored.
*
* If this operation results in the counter falling below 0 - an exception is raised.
*
* @throws IllegalStateException if the counter is below 0.
*/
public void decrement() {
int counterVal = counter.decrementAndGet();
if (counterVal == 0) {
// we've gone from non-zero to zero. That means we're idle now! Tell espresso.
if (null != resourceCallback) {
resourceCallback.onTransitionToIdle();
}
}
if (counterVal < 0) {
throw new IllegalArgumentException("Counter has been corrupted!");
}
}
}
EspressoIdlingResource.java
public class EspressoIdlingResource {
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 IdlingResource getIdlingResource() {
return mCountingIdlingResource;
}
}
确定。让我们转到活动,您需要耗费大量时间。首先,把这个方法放在底部。
@VisibleForTesting
public IdlingResource getCountingIdlingResource() {
return EspressoIdlingResource.getIdlingResource();
}
在你耗时的任务中。你应该告诉你的浓咖啡要这样等。
EspressoIdlingResource.increment();
yourTask.run(new Callback() {
void onFinish(){
EspressoIdlingResource.decrement();
}
})
最后一步是在你的UI测试类中定义这些方法。
@Before
public void registerIdlingResource() {
Espresso.registerIdlingResources(mOnBoardActivityTestRule.getActivity().getCountingIdlingResource());
}
/**
* Unregisters your idling resource so it can be garbage collected and does not leak any memory
*/
@After
public void unregisterIdlingResource() {
Espresso.unregisterIdlingResources(mOnBoardActivityTestRule.getActivity().getCountingIdlingResource());
}
是的。最后我们完成了。
你如何设置'mAdapter'? – tynn
动画是您在ui测试中的敌人,每个progres栏,自定义动画或任何正在非异步线程池上完成的工作都不会使用espresso进行注册,并且只会运行其他断言,因为它认为没有什么可以等待。也尝试编写你的测试,你注入并设置数据的设置和拆卸,然后你的活动将在积累期间。您是否在displayProducts()后调用notifydataset? – originx
mAdapter从哪里来?我认为你正在检查错误的适配器 – Tudor