由于新的安卓SDK使用ActivityScenarioRule替代了ActivityTestRule,我们期望ActivityScenarioRule能跟ActivityTestRule一样进行懒加载,但是实际并非如此。好像谷歌添加了ActivityScenarioRule懒加载功能但是还没有release出来。在实际使用中如果我们又有懒加载的需求,例如用RuleChain实现截图、重复测试等多个rule的使用,那么可以自定义一个ActivityScenario的TestRule。
自定义TestRule
open class CustomActivityScenarioTestRule <T : Activity> : TestRule {
lateinit var scenario: ActivityScenario<T>
override fun apply(base: Statement, description: Description): Statement {
return object : Statement() {
override fun evaluate() {
try {
base.evaluate()
} finally {
// if (this@CustomActivityScenarioTestRule::scenario.isInitialized) {
// finishActivity()
// }
}
}
}
}
fun launchActivity(intent: Intent) {
scenario = ActivityScenario.launch(intent)
}
fun finishActivity() {
scenario.close()
}
}
scenario.close()也可以放在evaluate的finally里,这样不用每次测试结束都去主动调用一次scenario.close, 但使用中发现放在finally里每次测试结束scenario.close会被自动调用两次,所以可以将scenario.close放在每次测试结束调用的@After里。
引用CustomTestRule
@get:Rule
var activityScenarioRule = CustomActivityScenarioTestRule<MainActivity>()
private val flakyRule = FlakyTestRule()
@get:Rule
var chain = RuleChain.outerRule(flakyRule)
.around(activityScenarioRule)
另外,调用scenario.close()结束时经常会出现延时45秒才能结束的情况,主要原因是scenario.close()调用了moveToState,里面用了CountDownLatch有锁竞争,而latch.await的默认超时时间是45秒。这个等待时间是难以忍受的。
可以通过以下方式设置对超时时间进行控制。
companion object {
const val ACTIVITY_LIFECYCLE_CHANGE_TIMEOUT_MILLIS_KEY = "activityLifecycleChangeTimeoutMillis"
const val ACTIVITY_LIFECYCLE_CHANGE_TIMEOUT_MILLIS_VALUE = "3000"
}
fun setupInstrumentTimeout() {
val instrumentation = InstrumentationRegistry.getInstrumentation();
val bundle = Bundle();
bundle.putString(ACTIVITY_LIFECYCLE_CHANGE_TIMEOUT_MILLIS_KEY, ACTIVITY_LIFECYCLE_CHANGE_TIMEOUT_MILLIS_VALUE);
InstrumentationRegistry.registerInstance(instrumentation, bundle);
}
@Before
fun beforeTests() {
setupInstrumentTimeout()
...
}
在测试@Before中对超时时间进行设置后,调用scenario.close()时会很快结束测试。