I am trying to test RecyclerView with AndroidJunit4, it is my test code:
@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));
}
Here is my code for displayProducts() in Activity:
@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);
}
}
It is giving error like:
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)
Please help what is the problem in my code?
The reason is that your Espresso test did not wait your loading task which is time-consuming. You need to use a espresso-idling-resource
to tell it to wait this task to finish.
Then you need a class to implement IdlingResource
and declare it your Activity.
When your Espresso test run, it will know and wait your long-time consuming task to complete and test the result.
Firstly, add its dependency.
compile "com.android.support.test.espresso:espresso-idling-resource:2.2.2"
Secondly, you need two Java files in folder src/main/java/your-package.
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;
}
}
Ok. Let's go to Activity where you have a time-consuming task. Firstly, put this method at the bottom.
@VisibleForTesting
public IdlingResource getCountingIdlingResource() {
return EspressoIdlingResource.getIdlingResource();
}
Inside your time-consuming task. you should tell your Espresso to wait like this.
EspressoIdlingResource.increment();
yourTask.run(new Callback() {
void onFinish(){
EspressoIdlingResource.decrement();
}
})
Final step is to define these methods in your UI test class.
@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());
}
Yeah. Finally we done.
There is one problem I can see here, your are inquiring the List size before the Main/UI thread is able to update it. So, you will have to wait in the current thread till the Activity finished updating the list on Main thread.
You can do,
Thread.sleep(500);
in the Test class to wait, to test the list setting behavior in Activity and you will find the assertion to be valid.
Since, the main thread runs infinitely till the application is running, you will have to implement a callback interface provided by the Activity to be informed about when populating the list is finished.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.