找到你要的答案

Q:Correct way to use IdlingResource in Espresso Android

Q:在意大利浓咖啡的Android应用idlingresource正确方法

I'm writing UI tests with Espresso. App cooperates tightly with server, so in many cases, I need to wait for either value to be calculated, or data is got and displayed, etc. Espresso suggests using IdlingResource for this. My IdlingResource classes look like this (simple and clear example).

public class IRViewVisible implements IdlingResource {

private View view;
private ResourceCallback callback;

public IRViewVisible(View view) {
    this.view = view;
}

@Override
public String getName() {
    return IRViewVisible.class.getName();
}

@Override
public boolean isIdleNow() {
    if(view.getVisibility() == View.VISIBLE && callback != null) {
        callback.onTransitionToIdle();
        return true;
    }
    return false;
}

@Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
    this.callback = resourceCallback;
}
}

Please correct me if I'm wrong anywhere (as sometimes it seems to me that my IdlingResources do not work properly). I register the idling resource in setUp() like this:

IRViewVisible ir = new IRViewVisible(View v);
Espresso.registerIdlingResources(ir).

Unregister it on tearDown().

I found this article (there is a section called "Register a component tied to an Activity instance") — I do not use his schema, but I checked hashcode of view that was set to IdlingResource after registering (in each method), and it's not the same view — all hashes are different.

Another question: One Test class (it's results) can't have any effect on another Test class, can it?

I'm writing UI tests with Espresso. App cooperates tightly with server, so in many cases, I need to wait for either value to be calculated, or data is got and displayed, etc. Espresso suggests using IdlingResource for this. My IdlingResource classes look like this (simple and clear example).

public class IRViewVisible implements IdlingResource {

private View view;
private ResourceCallback callback;

public IRViewVisible(View view) {
    this.view = view;
}

@Override
public String getName() {
    return IRViewVisible.class.getName();
}

@Override
public boolean isIdleNow() {
    if(view.getVisibility() == View.VISIBLE && callback != null) {
        callback.onTransitionToIdle();
        return true;
    }
    return false;
}

@Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
    this.callback = resourceCallback;
}
}

Please correct me if I'm wrong anywhere (as sometimes it seems to me that my IdlingResources do not work properly). I register the idling resource in setUp() like this:

IRViewVisible ir = new IRViewVisible(View v);
Espresso.registerIdlingResources(ir).

在teardown()注销。

我发现这篇文章(有一条叫“登记组件绑定到一个活动实例”)-我不使用自己的模式,但我检查来看,是集idlingresource注册后的hashCode(每个方法),和它不一样的观点--所有的哈希值是不同的。

另一个问题:一个测试类(它的结果)不能对另一个测试类产生任何影响,对吗?

answer1: 回答1:

I'm guessing your problem stems from getName() returning the same name for all instances of IRViewVisible. This means you can only have one registered instance of it at a time - any subsequent registrations will fail (silently!).

You mention that you clear the IdlingResources at the end of each test, but if you are register multiple instances of it at once, you need to make sure each instance has a unique name. it's not clear from your question if you're registering multiple instances of IRViewVisible in a single test.

As to your final question: Yes, it is possible. Android doesn't completely shut down the Application between test runs - just the Activities. Common things which can cause problems:

  • Failing to clear persistent state (saved data).
  • Failing to clear global state - e.g. static variables/singletons
  • Not waiting for background threads to finish running.

As an aside, it's worth noting that you only call onTransitionToIdle() inside isIdleNow(). This works (thanks @Be_Negative for the heads up!) but it could slow down your tests a lot, since Espresso will only poll isIdleNow() every few seconds. If you call onTransitionToIdle() as soon as the view becomes visible, it should speed things up considerably.

I needed something similar to your IRViewVisible myself, here's my effort.

我猜你的问题源于getname()返回相同的名称为irviewvisible所有实例。这意味着你一次只能注册一个注册实例,任何后续的注册都会失败(默默!)。

你说你清楚的idlingresources在每次试验结束,但如果你是在一次登记的多个实例,你需要确保每个实例都有一个唯一的名称。目前尚不清楚你的问题,如果你在一个单一的测试irviewvisible注册多个实例。

至于你最后的问题:是的,这是可能的。Android没有完全关闭测试运行之间的应用程序-只是活动。常见的事情,可能会导致问题:

  • Failing to clear persistent state (saved data).
  • Failing to clear global state - e.g. static variables/singletons
  • Not waiting for background threads to finish running.

另外,值得注意的是,ontransitiontoidle()里面isidlenow()只打电话给你。这部作品(感谢@ be_negative的头!)但它可以减缓你的测试很多,因为意大利浓咖啡只会投票isidlenow()每隔几秒钟。如果你打电话给ontransitiontoidle()只要视线变得可见,它应该加快速度相当。

我需要你的irviewvisible类似于自己,这是我的努力。

answer2: 回答2:

Well, first of all you shouldn't need to use Espresso IdlingResource to test server calls. If you use AsyncTasks in your server calls, Espresso will be able to know when to be idle and when not. If this is not enough: try to refactor your code in this way:

  IRViewVisible idlingResource = new IRViewVisible(yourView);
  IdlingPolicies.setMasterPolicyTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
        IdlingPolicies.setIdlingResourceTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);

        // Now we wait
        Espresso.registerIdlingResources(idlingResource);

        // Stop and verify


        // Clean up
        Espresso.unregisterIdlingResources(idlingResource);

Hope to be helpful.

嗯,首先,你不需要使用意大利浓咖啡idlingresource测试服务器调用。如果你使用你的服务器asynctasks称,意大利浓咖啡将能够知道什么时候是空闲的时候不。如果这是不够的:试图重构代码以这种方式:

  IRViewVisible idlingResource = new IRViewVisible(yourView);
  IdlingPolicies.setMasterPolicyTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
        IdlingPolicies.setIdlingResourceTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);

        // Now we wait
        Espresso.registerIdlingResources(idlingResource);

        // Stop and verify


        // Clean up
        Espresso.unregisterIdlingResources(idlingResource);

希望对大家有所帮助。

answer3: 回答3:

So the isIdleNow() method will never return true if you don't set a callback to the idlingResource? I reckon it's better to refactor it like this:

@Override
public boolean isIdleNow() {
    boolean idle = view.getVisibility() == View.VISIBLE;
    if(idle && callback != null) {
        callback.onTransitionToIdle();
    }
    return idle;
} 

So the isIdleNow() method will never return true if you don't set a callback to the idlingResource? I reckon it's better to refactor it like this:

@Override
public boolean isIdleNow() {
    boolean idle = view.getVisibility() == View.VISIBLE;
    if(idle && callback != null) {
        callback.onTransitionToIdle();
    }
    return idle;
} 
android  automated-tests  android-espresso