Controlling when an automation test ends - Espress

2019-05-26 06:51发布

问题:

I have an unusual situation I am testing. I am using Espresso to write my tests. I know Espresso and InstrumentationTestCase is not meant to do this.

I have a Listener I created in one of my classes that will notify me of a change of a certain value. I use the listener in my test suite.

When I get the value from the listener, I need to assert the value was changed as such.

My problem is the test will end before I will receive the value form the listener.

    private void sendSpeedChanges() {
    setStaticSpeed(new Random().nextInt(10) + 2);
    try {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                consoleActivity.onSpeedChanged(getStaticSpeed(), false);
            }
        });
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }

}

private void createSpeedDelegate() {
    EspressoMachineValues.setOnSpeedChangeListener(new EspressoMachineValues.OnSpeedChangeListener() {
        @Override
        public void onSpeedChanged(double speed) {
            //assert speed is correct.
            assertTrue(getStaticSpeed() == speed);
        }
    });

}

These are the two methods I am using. The createSpeedDelegate() is call at the very beginning. Then I call sendSpeedChanges. I need to do this X-amount of times.


NOTE:

  • It takes about 200 milliseconds to retrieve info (On average).
  • I can't call sendSpeedChanges() until I have checked the value in onSpeedChange()
  • I cannot use Thread.sleep(); because the listener is on the main thread.

I have tried adding a getInstrumentation().wait(2000); and also getInstrumentation().waitForIdleSync(); Obviously, neither work.

In a perfect world, I would do this:

   for (int i = 0; i < 42; i++) {
        sendSpeedChanges();
        i++;
    }

But, this will not wait for the value to be checked. And if I do wait for the value, the test runner thinks all tests are done and terminates.

My question is, would there be a way to control when the test quits? Even though my tests appear to be done.

回答1:

In your test you will need to create a control statement that keeps that test running as long as you want it to be run.

while(myTestNeedsToRun) {
    if(speedChangeReceived) {
        sendSpeedChange();
        speedChangeReceived = false;
    }
}

private void createSpeedDelegate() {
   EspressoMachineValues.setOnSpeedChangeListener(new EspressoMachineValues.OnSpeedChangeListener() {
    @Override
    public void onSpeedChanged(double speed) {
        //assert speed is correct.
        assertTrue(getStaticSpeed() == speed);
        speedChangedReceived = true;
    }
});

Once you decide you are finished running your test just set myTestNeedsToRun = false and then your test will end.



回答2:

Alternatively, you could create an IdlingResource to monitor your speed. IdlingResource is the way Espresso uses to verify the Main Thread is idle or that there is no AsyncTasks running in the AsyncTask pool.

Have a loook at coutingIdlingResource class in the library source code. You could implement something similar to that. In your case, it could be something like this:

[...]

private int mTargetSpeed;
private volatile ResourceCallback resourceCallback;

@Override
public boolean isIdleNow() {
  boolean isIdle = false;
  if (getStaticSpeed() == mTargetSpeed) {
     isIdle = true;
     resourceCallback.onTransitionToIdle();
  } else {
     isIdle = false;
  }

  return isIdle;
}

On your tests, whenever you want to wait for the speed to reach the desired level, you should do:

[...]
SpeedIdlingResource speedIdlingResource = new SpeedIdlingResource ("my_idling_resource");
Espresso.registerIdlingResources(speedIdlingResource);

This way, Espresso will block until your idling resource tells the framework your SpeedMonitor is idle. That's goode because you leverage all Espresso synchronization framework to monitor when you reached the target speed, so your tests would be more reliable and faster than making a occupied wait.