如何使用Espresso旋转Activity,我指的是:屏幕方向变化?

29

我决定将应用程序测试与Google的Espresso进行测试的标准之一设定为:

屏幕方向旋转后,测试应该保持Activity状态不变。

当我使用Espresso时,如何旋转屏幕?


我尝试了以下Robotium代码(是的,我在我的Espresso测试中放置了Robotium代码,所以你可以起诉我)

solo.setActivityOrientation(solo.LANDSCAPE);
solo.setActivityOrientation(solo.PORTRAIT);

但是当我在我的Espresso测试中运行它时,它会导致应用程序崩溃。
有没有什么办法可以解决这个问题?

提前感谢您的任何帮助


请查看这里的被接受的答案:https://dev59.com/DnA75IYBdhLWcg3wBkO1 - Clive Seebregts
7个回答

21

如果您的测试用例中只有一个Activity,您可以执行以下操作:

1. 声明您的测试规则

@Rule
public ActivityTestRule<TestActivity> mActivityTestRule = new ActivityTestRule<>(TestActivity.class);

2. 获取您的Activity并应用屏幕旋转。

mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

那太容易了!


2
这只是解决方案的一部分。看起来你需要稍等一下。 - 0xcaff
抱歉,但看起来它是有效的: https://github.com/egslava/edittext-mask/blob/master/MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/MainActivityTest.java#L91 - Slava

17
您可以使用uiautomator库进行操作。
dependencies {
  androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' 
}

UI Automator需要最低SDK版本为18,因此如果您的应用程序具有较低的最小SDK版本,则需要在androidTest文件夹中创建一个新的AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:tools="http://schemas.android.com/tools"
    package="your.package.name">
    <uses-sdk tools:overrideLibrary="android.support.test.uiautomator.v18"/>
</manifest>

然后在你的测试中

UiDevice device = UiDevice.getInstance(getInstrumentation());

device.setOrientationLeft();
device.setOrientationNatural();
device.setOrientationRight();

这是处理测试时方向的最佳且干净的方法。 - TeeTracker
如果设备禁用了自动旋转,这段代码就无法正常工作。有没有什么解决办法? - Kirk
@Kirk 你确定吗?如果我没记错的话,它应该可以工作。 - lelloman
@Kirk,我刚在我的安卓9手机上测试了一下,即使关闭了自动旋转,它也可以旋转。 - lelloman
使用AndroidX,Gradle依赖现在是androidx.test.uiautomator:uiautomator:2.2.0 - anotherdave
我是一个严格要求在Jellybean(SDK 16)中进行测试的人,除非整个项目都依赖于它,因此我尝试并成功地使用以下代码而不需要额外的库: InstrumentationRegistry.getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0); InstrumentationRegistry.getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_270); - Philip Young

7

这个更完整的解决方案创建了一个自定义的Espresso ViewAction,并且运行良好。它展示了如何在调用setRequestedOrientation()方法之前获取Activity(即使它是一个AppCompatActivity)。它还有一个清晰的调用接口:

onView(isRoot()).perform(orientationLandscape()); 
onView(isRoot()).perform(orientationPortrait());

我在每次屏幕方向变化后都会加入100毫秒的延迟,但你可能不需要这么做。


5
如何旋转屏幕:
public static void rotateScreen(Activity activity) {
    final CountDownLatch countDownLatch = new CountDownLatch(1);
    final int orientation = InstrumentationRegistry.getTargetContext()
            .getResources()
            .getConfiguration()
            .orientation;
    final int newOrientation = (orientation == Configuration.ORIENTATION_PORTRAIT) ?
            ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE :
            ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;

    activity.setRequestedOrientation(newOrientation);

    getInstrumentation().waitForIdle(new Runnable() {
        @Override
        public void run() {
            countDownLatch.countDown();
        }
    });

    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        throw new RuntimeException("Screen rotation failed", e);
    }
}
Activity 可以从 ActivityRule 中获取。

2
您可以使用 getInstrumentation().waitForIdleSync() 代替 CountDownLatch - 0xcaff

1
你不能混合使用Robotium和Espresso测试。有时解决问题的最好方法是检查所需但不兼容方法的源代码。
我相信你已经有了像这样的setUp()方法,其中包含如下代码:
myActivity = this.getActivity();
使用此方法更改屏幕方向:

myActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

or

myActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

您可能还需要使用 myActivity.getInstrumentation().waitForIdleSync();Thread.sleep(milliseconds); 来等待旋转结束,因为它是以异步方式执行的。第二种方法取决于模拟器/设备,所以请明智选择。

希望能对您有所帮助。


1
此外,如果您正在使用ActivityTestRule来访问您的活动,则文档指出该类已被弃用,最好使用ActivityScenarioRule。
而不是直接访问活动的属性,您需要将与活动的交互放在可运行回调中。
因此,屏幕旋转示例可能如下所示:
    @get:Rule
    val activityRule = ActivityScenarioRule(MainActivity::class.java)

    private fun rotate() {
        activityRule.scenario.onActivity {
            it.requestedOrientation =
                    ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
        }
    }

附言:不确定使用哪个常量是正确的,但ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE(或USER_PORTRAIT)是适用于我的。


0

在我自己测试方向时遇到了麻烦,我想补充一下,虽然lelloman建议使用UiDevice是正确的,但从文档的角度来看 - 不幸的是,在某些情况下它不起作用。

我发现至少在API 23模拟器上,测试崩溃后旋转可能会卡住:

  1. 执行uiDevice.setOrientationLeft()
  2. 应用程序崩溃;
  3. 旋转被卡住;
    3.1 通过UiDevice强制旋转可以解决问题,但当测试结束时,旋转会回到错误的状态,直到您手动更改旋转为“自动旋转”;
    3.2 uiDevice.unfreezeRotation()在测试运行时有所帮助,但在测试结束后,旋转会回到错误的状态。

我在API 28上没有这个问题。

因此,我发现使用setRequestedOrientation是我唯一的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接