Instrumented Testで画面を動かしている途中で画面が消灯してしまうと、多くの場合テストに失敗する。
ということで、その対処法をお手軽順に書いておく。
スリープモードにしない
設定の[開発者向けオプション]-[スリープモードにしない]を有効にする。
常用していない端末ならこれで済む。
常用端末を開発でも使っている場合は、この機能は必ずしも嬉しくないので次へ。
UiDevice#wakeUp()
UIAutomatorのAPIで、定期的に起こす案。
実行時間が長いテストは多くの場合何かしらの繰り返しになっているはずで、繰り返しの先頭にこれを入れれば何となく動く(かもしれない)。
かなり雑な対応で、必ず成功するかはなんとも言えない。
とはいえ、これを一箇所入れれば解決する、ということであれば選択肢としてはあり。
@RunWith(AndroidJUnit4::class)
class MainActivityTest {
@Rule
@JvmField
val rule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java, false, false)
lateinit var uiDevice: UiDevice
@Before
fun setup() {
uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
}
@Test
fun test() {
for (i in 0..100) {
uiDevice.wakeUp()
// test code
}
}
}
ActivityTestRuleを拡張する
ActivityTestRuleを継承したクラスを作成し、WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ONを使って画面点灯状態を維持する。
ActivityからTYPE_APPLICATIONにaddViewする場合はパーミッション不要なので、変更箇所も少なくて済む。
API25〜27で動作確認済み。おそらく19とかでも動くと思う。
class FooActivityTestRule<T : Activity> : ActivityTestRule<T> {
lateinit var view: View
lateinit var windowManager: WindowManager
constructor(cls: Class<T>) : super(cls)
constructor(cls: Class<T>, initialTouchMode: Boolean) : super(cls, initialTouchMode)
constructor(cls: Class<T>, initialTouchMode: Boolean, launchActivity: Boolean) : super(cls, initialTouchMode, launchActivity)
override fun afterActivityLaunched() {
super.afterActivityLaunched()
runOnUiThread {
windowManager = activity.windowManager
view = View(activity)
windowManager.addView(view, WindowManager.LayoutParams(0, 0
, WindowManager.LayoutParams.TYPE_APPLICATION
, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
, PixelFormat.TRANSLUCENT))
}
}
override fun finishActivity() {
runOnUiThread {
windowManager.removeViewImmediate(view)
}
super.finishActivity()
}
}
テストコードの方は、ActivityTestRuleを置き換えるだけで良い。
@RunWith(AndroidJUnit4::class)
class MainActivityTest {
@Rule
@JvmField
// val rule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java, false, false)
// ↓
val rule: ActivityTestRule<MainActivity> = FooActivityTestRule(MainActivity::class.java, false, false)
@Test
fun test_all() {
// test code
}
}