22

我一直在用 androids new espresso 框架编写测试,发现它运行良好。一件烦人的事情(不是浓缩咖啡特有的)是我必须确保我的屏幕处于唤醒状态并解锁才能运行测试。我找到了一种解决方法(通过各种来源),但是我不确定集成它的最佳方法。

所以这就是我所做的,在我的“家庭”活动中,我有以下代码:

家庭类:

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);
}

您还需要添加以下权限:

<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

因此,在完成此操作后,我的测试现在唤醒我的手机运行,这样我就不必站岗并确保屏幕在测试开始之前不会关闭。

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

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

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

4

9 回答 9

16

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

src/debug/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>

当应用程序为调试而构建时,上述权限将合并到主清单中。默认情况下,构建系统使用调试构建进行仪器测试,因此可以正常工作。

然后在我的 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);
    }
    ...
}

现在我的手机可以运行测试,而无需我先手动唤醒它们,而且我不必将上述权限添加到我的应用程序的发布版本中。

于 2013-11-13T19:52:16.360 回答
9

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

adb -s $DEVICE_ID shell input keyevent 82

这将解锁您的设备屏幕。

于 2015-05-25T20:32:24.727 回答
9

现在 KeyguardLock 已被弃用,您可以简单地使用:

    if (BuildConfig.DEBUG) {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
    }
于 2016-02-09T08:00:08.870 回答
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);

    }
于 2014-04-22T14:58:16.583 回答
3

尽管您已经接受了 Matt Wolve 的回答,但我认为使用测试样板污染您的代码并不是一个好主意(我知道使用 Espresso 在某些情况下您必须这样做,例如为自定义 IdlingResources 添加空闲标志)。我想添加另一种方法:

    @ClassRule
    public static ActivityTestRule<HomeActivity> mActivityRuleSetUp = new ActivityTestRule<>(
            HomeActivity.class);


    private static void wakeUpDevice(){
        if (BuildConfig.DEBUG){
            HomeActivity homeActivity = mActivityRuleSetUp.getActivity();

            KeyguardManager myKM = (KeyguardManager) homeActivity.getSystemService(HomeActivity.KEYGUARD_SERVICE);
            boolean isPhoneLocked = myKM.inKeyguardRestrictedInputMode();

            if (isPhoneLocked){
                homeActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                        | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
            }
        }
     }


    @BeforeClass
    public static void setUp(){
        wakeUpDevice();
    }

希望能帮助到你。

于 2017-11-12T18:35:50.463 回答
1

为了测试设备,在 Settings->Security 中将 Lock pattern 设置为 NONE 然后使用实例UiDevice并调用其wakeUp()方法

如果屏幕关闭,此方法模拟按下电源按钮,否则如果屏幕已经打开,则它不执行任何操作。如果屏幕关闭并且刚刚打开,此方法将插入 500 毫秒延迟,以让设备有时间唤醒并接受输入。

于 2016-03-18T13:25:09.087 回答
1

另一种在测试前唤醒设备的最佳方法。只需添加ActivityLifecycleCallback您的setUp方法。

public class Moduletest extends ActivityInstrumentationTestCase2<Your Activity>{

 protected void setUp(){
    super.setUp();

    ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(new ActivityLifecycleCallback() {
      @Override public void onActivityLifecycleChanged(Activity activity, Stage stage) {
        if (stage == Stage.PRE_ON_CREATE) {
          activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
      }
    });
  }
}
于 2016-11-09T11:42:27.550 回答
1

我是这样做的:首先制定两条规则,一条用于活动,一条用于 UI 线程:

@Rule
public ActivityTestRule<Your Activity> mActivityRule =
        new ActivityTestRule<>(Your Activity.class, true, true);

@Rule
public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();

然后在我的第一个测试方法中做了这个:

   @Test
   @LargeTest
   public void CreateAndSaveTaskEntity() throws Throwable {

            uiThreadTestRule.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Your Activity activity = mActivityRule.getActivity();
            activity.getWindow()
                    .addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
                            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
                            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);

                }
            });

            //begin test cases

            ...
    }

当然,您必须添加AndroidManifest.xml权限:

<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
于 2017-03-23T11:11:07.920 回答
1

这是一种使用任何已弃用的 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)
    }
}

选项 2:规则

@RunWith(AndroidJUnit4::class)
class MyActivityTest {

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

    @get:Rule
    val screenLockRule = RunWhenScreenOffOrLockedRule()
}

/**
* 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()
            }
        }
    }
}
于 2021-11-11T15:04:17.847 回答