The original blog is Espresso: Elapsed time.
When do you need to write the test that needs to wait, you need to use IdlingResource
. Because Espresso does not wait for you.
Create simple elapsed time application, with one button and one text view. When to clicking the start button, the number will run until click stop button.
We will write the test to click the start button, wait and click stop. Let’s go!
Setup
Add instrumentation runner
and espresso dependencies
.
defaultConfig { ... testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' }
dependencies { androidTestCompile ('com.android.support.test:runner:0.5') androidTestCompile ('com.android.support.test:rules:0.5') androidTestCompile ('com.android.support.test.espresso:espresso-core:2.2.2') androidTestCompile ('com.android.support.test.espresso:espresso-idling-resource:2.2.2') }
Create Idling Resource
public class ElapsedTimeIdlingResource implements IdlingResource { private final long startTime; private final long waitingTime; private ResourceCallback resourceCallback; public ElapsedTimeIdlingResource(long waitingTime) { this.startTime = System.currentTimeMillis(); this.waitingTime = waitingTime; } @Override public String getName() { return ElapsedTimeIdlingResource.class.getName() + ":" + waitingTime; } @Override public boolean isIdleNow() { long elapsed = System.currentTimeMillis() - startTime; boolean idle = (elapsed >= waitingTime); if (idle) { resourceCallback.onTransitionToIdle(); } return idle; } @Override public void registerIdleTransitionCallback(ResourceCallback callback) { resourceCallback = callback; } }
Create Custom Matcher
The IdlingResource
is not waiting on exactly time when we specific. So, we need to check it waiting for more than we specific time instead.
public class MoreThanMatcher { public static Matcher moreThan(final int expectedValue) { return new BoundedMatcher<View, TextView>(TextView.class) { @Override protected boolean matchesSafely(TextView textView) { float actualValue = Float.valueOf(textView.getText().toString()); return (int) actualValue == expectedValue; } @Override public void describeTo(Description description) { description.appendText("more than: " + expectedValue); } }; } }
Write Test
Create test class and add annotation. Make sure that created it in androidTest
, not test package.
@RunWith(AndroidJUnit4.class) public class MainActivityTest { }
Add activity test rule.
@Rule public ActivityTestRule activityTestRule = new ActivityTestRule<>(MainActivity.class);
Reset timeout before run each test. Because we need to modify timeout policy for each test.
@Before public void resetTimeout() { IdlingPolicies.setMasterPolicyTimeout(60, TimeUnit.SECONDS); IdlingPolicies.setIdlingResourceTimeout(26, TimeUnit.SECONDS); }
It will default time out of Espresso, if the app has been idle
is 60 seconds and it will default time out of IdlingResource
, if app has been idle
is 26 seconds.
public final class IdlingPolicies { private IdlingPolicies() { } private static volatile IdlingPolicy masterIdlingPolicy = new IdlingPolicy.Builder() .withIdlingTimeout(60) .withIdlingTimeoutUnit(TimeUnit.SECONDS) .throwAppNotIdleException() .build(); private static volatile IdlingPolicy dynamicIdlingResourceErrorPolicy = new IdlingPolicy.Builder() .withIdlingTimeout(26) .withIdlingTimeoutUnit(TimeUnit.SECONDS) .throwIdlingResourceTimeoutException() .build(); ... }
Write waitFor
method to set new timeout policy for use the test is not timeout before it done. So, we set the new timeout to double of waitingTime
. Then register own IdlingResource
to Espresso and make sure that unregister it after the test is done.
private void waitFor(int waitingTime) { onView(withId(R.id.toggle_button)) .check(matches(withText(R.string.start))) .perform(click()); // Make sure Espresso does not time out IdlingPolicies.setMasterPolicyTimeout(waitingTime * 2, TimeUnit.SECONDS); IdlingPolicies.setIdlingResourceTimeout(waitingTime * 2, TimeUnit.SECONDS); IdlingResource idlingResource = new ElapsedTimeIdlingResource(DateUtils.SECOND_IN_MILLIS * waitingTime); Espresso.registerIdlingResources(idlingResource); onView(withId(R.id.toggle_button)) .check(matches(withText(R.string.stop))) .perform(click()); onView(withId(R.id.elapsed_Time)) .check(matches(moreThan(waitingTime))); Espresso.unregisterIdlingResources(idlingResource); } }
Then use it to write the test.
@Test public void waitFor5Seconds() { waitFor(5); } @Test public void waitFor65Seconds() { waitFor(65); }
Here the result.
Source code: GitHub
Dude, I don“t have anything else to say, but thanks a lot, you have helped me more than any other blog or tutorial about this topic, THANKS