Android Espresso,测试前唤醒设备.如何使用自定义清单进行测试?

Mat*_*lfe 21 android android-wake-lock android-testing android-espresso

我一直在用androids新的espresso框架编写测试,并发现它运行良好.一个烦人的事情(特别是浓缩咖啡)是我必须确保我的屏幕醒来并解锁以便运行测试.我找到了一种解决方法(通过各种来源),但我不确定整合它的最佳方法.

所以这就是我所做的,在我的"Home"活动中,我有以下代码:

Home.class:

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /************ Put this in a conditional for a test version ***********/
    KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
    KeyguardManager.KeyguardLock keyguardLock = km.newKeyguardLock("TAG");
    keyguardLock.disableKeyguard();
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
Run Code Online (Sandbox Code Playgroud)

您还需要添加以下权限:

<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
Run Code Online (Sandbox Code Playgroud)

所以在这样做之后,我的测试现在唤醒我的手机运行所以我没有必须站岗并确保屏幕在测试开始之前没有关闭.

我宁愿不在我的应用程序中包含这些权限.我知道使用gradle可以制作具有自己的android清单的不同"风味",它将合并到主清单中.我正在考虑使用它,但我不想仅仅因为这个已经使用测试构建类型来运行而添加了一种风味.从android gradle文档看起来,您无法为instrumentTest目录创建AndroidManifest,因为它将自动生成.

但是,我想知道是否有另一种方法可以在不创建变量的情况下执行此操作,然后指定测试应该运行该变体.此外,我不确定所有这些的确切语法,并认为只是为了其他人在网站上有这些信息会很好,因为它似乎分散了.

最后,如果有人知道更好的方法来解决唤醒手机测试的问题,我很乐意听到它,因为我不是这种方式的忠实粉丝,我正在尝试.

Mat*_*lfe 15

我实际上想出了一个非常简单的方法来处理这个问题.从主清单中删除keyguard和wakelock权限,并将它们放在src/debug/AndroidManifest.xml中,如下所示:

SRC /调试/ AndroidManifest.xml中

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
    <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
</manifest>
Run Code Online (Sandbox Code Playgroud)

当应用程序构建用于调试时,上述权限将合并到主清单中.默认情况下,构建系统使用调试版本进行仪器测试,因此这很好.

然后在我的onCreate中我把问题中提到的代码:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (BuildConfig.DEBUG) {
        KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
        KeyguardManager.KeyguardLock keyguardLock = km.newKeyguardLock("TAG");
        keyguardLock.disableKeyguard();
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

现在我的手机可以运行测试,而不是我先用手唤醒它们,我没有必要将上述权限添加到我的应用程序的发布版本.

  • 为什么要修改活动代码以满足单元测试的要求?这似乎是一种反模式...... (4认同)

den*_*nys 9

如果从CI环境运行测试,最简单的方法是使用如下所示的adb命令:

adb -s $DEVICE_ID shell input keyevent 82
Run Code Online (Sandbox Code Playgroud)

这将解锁您的设备屏幕.

  • 在我看来,这是实现这一目标的最佳解决方案.它可以很容易地添加为任何构建系统的构建步骤. (3认同)
  • `input keyevent 3`(`KEYCODE_HOME`)比其他键更合适.如果此时屏幕已开启,则密钥代码26(`KEYCODE_POWER`)可能会关闭屏幕. (2认同)

Rap*_*l C 9

现在不推荐使用KeyguardLock,您只需使用:

    if (BuildConfig.DEBUG) {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
    }
Run Code Online (Sandbox Code Playgroud)


use*_*372 5

我已经按照 Matt 的建议创建了 src/debug/AndroidManifest.xml 文件,并将以下代码添加到 testCase 中:

   @Override
    public void setUp() throws Exception {
        super.setUp();
        // Espresso will not launch our activity for us, we must launch it via getActivity().
        Activity activity = getActivity();
        KeyguardManager km = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE);
        KeyguardManager.KeyguardLock keyguardLock = km.newKeyguardLock("TAG");
        keyguardLock.disableKeyguard();
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

    }
Run Code Online (Sandbox Code Playgroud)


rya*_*en8 5

这是一种不使用任何已弃用的 API、没有明显权限的方法,即使设备设置了锁针也能正常工作。

选项 1:在 @Before 中

@RunWith(AndroidJUnit4::class)
class MyActivityTest {

    // Replace with your own Activity test rule.
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Before
    fun setUp() {
        UiDevice.getInstance(getInstrumentation()).wakeUp()
        composeTestRule.activity.setShowWhenLocked(true)
    }
}
Run Code Online (Sandbox Code Playgroud)

选项 2:规则

@RunWith(AndroidJUnit4::class)
class MyActivityTest {

    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @get:Rule
    val screenLockRule = RunWhenScreenOffOrLockedRule()
}
Run Code Online (Sandbox Code Playgroud)
/**
* This rule will allow the tests to run even if the device's screen is off or locked.
* Allows a developer to fire and forget running the UI Test across different devices or on the CI
* emulator.
*/
class RunWhenScreenOffOrLockedRule : TestRule {
    override fun apply(base: Statement, description: Description): Statement {
        return object : Statement() {

            override fun evaluate() {
                // Turn screen on
                UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).wakeUp()

                // Allow any activity to run when locked
                ActivityLifecycleMonitorRegistry
                    .getInstance()
                    .addLifecycleCallback { activity, stage ->
                        if (stage === Stage.PRE_ON_CREATE) {
                            activity.setShowWhenLocked(true)
                        }
                    }

                // Continue with other statements
                base.evaluate()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)