情况
在官方文档中:https://google.github.io/android-testing-support-library/docs/rules/index.html, 它说:
“该规则提供了单个活动的功能测试。
被测试的活动将在每个测试之前启动,注释为
@Test 以及任何用 @Before 注释的方法之前。这将是
测试完成后终止,所有方法注释为
@完成后。可以在以下期间访问被测试的活动
通过调用 ActivityTestRule#getActivity() 进行测试。”
从技术上讲是的,活动正在终止。但似乎无法保证这种情况何时会发生。例如。在为下一次测试再次创建之前,它不一定会发生。
问题
在我的一些测试中,我需要依赖每次测试后调用的片段 OnDestroy 或 OnDetach,before下一个测试开始。我有需要清除和重新创建的听众。
如果在当前测试中的 OnResume 之后调用前一个测试中的 onDestroy,则回调将被清除,并且视图不会更新并且测试失败。
如果之前测试中的 onDestroy 根本没有被调用,那么当前测试中的回调将引用错误的实例。同样,视图将不会更新并且测试将失败。
问题
-
这种行为是在设计时讨论的情况还是一个错误?到目前为止我无法在文档中找到这一点。
- 处理这个问题的最佳实践是什么?我怀疑其他人也遇到过这个问题。
Edit:我现在已经解决了第 2 部分。请参阅下面的解决方法部分。然而,如果有人可以通过引用官方资源来回答第一部分,那么我很乐意接受这个答案。这就是我在这里真正要问的。如果有人有一些想法,第二部分只是一个奖励。
证据
如果您想看到这种行为,只需要几分钟。使用这样的活动创建一个新项目:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
和这样的测试类:
@RunWith(AndroidJUnit4.class)
@LargeTest
public class EspressoLifecycleTest {
@Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule<>(MainActivity.class);
@Test
public void test1() {
}
@Test
public void test2() {
}
@Test
public void test3() {
}
@Test
public void test4() {
}
}
在 OnResume 和 OnDestroy 方法上放置断点,并在调试模式下运行测试套件。
执行此操作几次,您会发现 Activity 生命周期方法的调用顺序并不一致。例如。它可能会连续调用 OnResume 两次,然后调用 OnDestroy 一次,然后再次调用 OnResume 两次,然后调用 OnDestroy 三次,或者您可以想到的任何其他组合。当然,它总是以至少一个 OnResume 开始。有时,如果在最后,它甚至不会调用 OnDestroy,但这没关系。不好的是,由于这种不可预测的顺序,我的测试不稳定。
我知道这可能是故意的,并且可能有一种简单的方法来处理它,我只是没有足够幸运找到它。如果您知道这是什么,请在此处发布答案。我不在乎事后看来我的问题有多愚蠢,我在这个问题上花了很多时间。这几乎总是简单的事情,所以我准备好为答案感到尴尬。
解决方法
使用 onPause 而不是 OnDestroy 会产生副作用,即当我 startActivityForResult 时被调用,但在平板电脑模式下不会在后台片段中再次调用 onResume。我正在探索实现这项工作的方法,但尚未找到解决方案。
Edit:onPause 最终遇到了同样的问题 - 这就是我首先使用 onDetach 的部分原因。最终,有时我不想分离监听器,直到片段被销毁。
这引导我想到了下一个可行的想法!万岁!到目前为止,我正在为调用 Activity 创建回调,以实现它所要求的功能,only如果该特定回调不存在。事实证明这是一个坏主意。我这样做是为了将回调数量限制为所需的确切数量。动机是合理的,但实施需要所有这些回调清除。解决方案是在从片段调用每个回调时重新创建它。如果它为空,则不要创建它,always创建它并替换之前存在的任何内容。现在根本不需要清除它们(据我所知)。