Issue
I have an activity that can display different toasts depending on the status returned from a web service call.
I am writing a test class, and my first test tests that one of these toasts is displayed when there's a network error. Below is the test class:
@RunWith(AndroidJUnit4.class)
public class LoginActivityTest extends BaseTest {
@Rule
public final ActivityTestRule<LoginActivity> login = new ActivityTestRule(LoginActivity.class, true);
@Test
public void noNetwork() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
login.getActivity().onEventMainThread(new LoginResp(CopiaWebServiceClient.ResponseStatus.NETWORK_ERROR));
}
});
onView(withText(R.string.toast_no_network_connection))
.inRoot(withDecorView(not(is(login.getActivity().getWindow().getDecorView()))))
.check(matches(isDisplayed()));
}
}
So the noNetwork
test calls LoginActivity
's onEventMainThread(LoginResp loginResp)
method (this needs to run on the UI thread, hence my use of runOnMainSync
) with a network error status to prompt it to show the expected toast_no_network_connection toast.
This test works and runs and passes successfully.
This is my issue:
If I add a second test to the test class, the second test fails. This is the second test, identical to the first except that it passes a different error status to onEventMainThread(LoginResp loginResp)
so that a different toast will be shown:
@Test
public void serverErr() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
login.getActivity().onEventMainThread(new LoginResp(CopiaWebServiceClient.ResponseStatus.HTTP_SERVER_ERROR));
}
});
onView(withText(R.string.toast_operation_failure_app_error))
.inRoot(withDecorView(not(is(login.getActivity().getWindow().getDecorView()))))
.check(matches(isDisplayed()));
}
The second test fails with output: android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with string from resource id: <2131689669>[toast_operation_failure_app_error] value: Sorry, failure to complete operation due to application error.
However, watching the emulator while running the tests I see both the initial toast_no_network_connection
toast (expected by the first test), and then the toast_operation_failure_app_error
toast (expected by the second test). Why does the second test fail?
It has something to do with the tests running one after the other, because when I comment out the first test, the second test passes.
My onEventMainThread(LoginResp loginResp)
method in LoginActivity
has the following code that shows an appropriate toast based on status:
switch (status) {
case HTTP_UNAUTHORIZED:
DialogCreator.createAlertDialog(this, getString(R.string.dialog_msg_login_fail)).show();
break;
case NETWORK_ERROR:
Toast.makeText(this, getString(R.string.toast_no_network_connection), Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(this, getString(R.string.toast_operation_failure_app_error), Toast.LENGTH_SHORT).show();
}
Debugging the test I see that the first test enters the NETWORK_ERROR case, as expected, and the second test enters the switch statement's default
section, also as expected.
Solution
After some further playing with the tests I opted for an approach suggested by Eirik W's answer from Espresso checking if toasts are displayed (one on top of another)
I changed my production code slightly to add a @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) annotated Toast member to LoginActivity to enable an @After annotated method in LoginActivityTest cancel any showing toast after each test.
Answered By - user1310850
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.