简体   繁体   English

Android RecyclerView适配器项目计数在单元测试时返回0

[英]Android RecyclerView Adapter Item count is returning 0 on unit testing

I am trying to test RecyclerView with AndroidJunit4, it is my test code: 我正在尝试使用AndroidJunit4测试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));


    }

Here is my code for displayProducts() in Activity: 这是我在Activity中的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);
        }
    }

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. 原因是您的Espresso测试没有等待您的装载任务,这非常耗时。 You need to use a espresso-idling-resource to tell it to wait this task to finish. 您需要使用espresso-idling-resource告诉它等待此任务完成。

Then you need a class to implement IdlingResource and declare it your Activity. 然后你需要一个类来实现IdlingResource并将它声明为你的Activity。

When your Espresso test run, it will know and wait your long-time consuming task to complete and test the result. 当您的Espresso测试运行时,它将知道并等待您的长时间消耗任务来完成并测试结果。

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. 其次,在src / main / java / your-package文件夹中需要两个Java文件。
SimpleCountingIdlingResource.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 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. 让我们去Activity,你有一个耗时的任务。 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. 你应该告诉你的Espresso这样等待。

EspressoIdlingResource.increment();

  yourTask.run(new Callback() {
    void onFinish(){
      EspressoIdlingResource.decrement();
    }
  })

Final step is to define these methods in your UI test class. 最后一步是在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());
}

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. 我可以在这里看到一个问题,您在Main / UI线程能够更新之前询问List大小。 So, you will have to wait in the current thread till the Activity finished updating the list on Main thread. 因此,您必须在当前线程中等待,直到Activity完成更新主线程上的列表。

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. 在Test类中等待,测试Activity中的列表设置行为,你会发现断言是有效的。

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. 由于主线程无限运行直到应用程序运行,因此您必须实现 Activity提供的回调接口 ,以便在填充列表完成时获得通知。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM