【发布时间】:2017-12-01 15:51:34
【问题描述】:
我有一个 Activity 可以根据 Web 服务调用返回的状态显示不同的 toast。
我正在编写一个测试类,我的第一个测试测试是否在出现网络错误时显示其中一个 toast。下面是测试类:
@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()));
}
}
所以noNetwork 测试调用LoginActivity 的onEventMainThread(LoginResp loginResp) 方法(这需要在UI 线程上运行,因此我使用runOnMainSync)并带有网络错误状态以提示它显示预期的toast_no_network_connection吐司。
此测试有效并运行并成功通过。
这是我的问题:
如果我向测试类添加第二个测试,第二个测试会失败。这是第二个测试,与第一个测试相同,只是它将不同的错误状态传递给 onEventMainThread(LoginResp loginResp),以便显示不同的 toast:
@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()));
}
第二次测试失败,输出: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.
但是,在运行测试时观看模拟器,我看到了最初的toast_no_network_connection toast(第一次测试预期),然后是toast_operation_failure_app_error toast(第二次测试预期)。为什么第二次测试失败了?
这与一个接一个地运行的测试有关,因为当我注释掉第一个测试时,第二个测试通过了。
LoginActivity 中的 onEventMainThread(LoginResp loginResp) 方法具有以下代码,可根据状态显示适当的 toast:
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();
}
调试测试我看到第一个测试按预期进入 NETWORK_ERROR 情况,第二个测试按预期进入 switch 语句的 default 部分。
【问题讨论】:
-
“这与一个接一个地运行的测试有关,因为当我注释掉第一个测试时,第二个测试通过了”——您是否尝试过颠倒测试的顺序? IOW,总是第二次测试失败还是总是
R.string.toast_operation_failure_app_error失败?我从来没有对Toasts进行 Espresso 测试(我很惊讶这是可能的,因为View并没有严格地绑定到你的 UI,上次我检查过) -
是的,我颠倒了测试的顺序,发现第二个测试总是失败,所以toast_no_network_connection如果第二个就会失败。
-
嗯...不知道你能做什么。您可以尝试将这些合并到一个
@Test方法中,看看您会得到什么结果。我不确定为什么第二个活动实例会出现第一个没有的问题,但是对这些使用单个@Test方法会让您使用单个活动实例,这可能会让您解决问题。跨度> -
是的,我颠倒了测试的顺序,发现第二个测试总是失败,所以toast_no_network_connection如果第二个就会失败。当 second 测试失败时,失败的
NoMatchingViewException消息中包含的视图层次结构包含来自 first 测试的Toast。所以第一个测试的Toast似乎在“闲逛”,可以这么说,在它运行之后。 -
“所以第一个测试的 Toast 似乎在“徘徊”,可以这么说,在它运行之后”——它将在
Toast.LENGTH_SHORT停留一段时间。你的第二个Toast直到那时才会显示。