在没有 Thread.Sleep() 的情况下,在 Android Studio 中等待 UI 测试中的函数的最佳方法是什么?
What is the best way to await functions in UI testing in Android Studio without Thread.Sleep()?
我正在使用 Espresso 为我开发的 Android 应用编写一些自动化测试。所有测试都是自动化的,并且是 passing/failing 根据 UI 发生的情况。我通过 SonarQube 运行 代码来检测错误的编码实践,它告诉我不应使用 Thread.Sleep()。
我主要在输入表单并需要隐藏键盘以向下滚动以点击下一个表单字段等的情况下使用 Thread.sleep()。根据我的理解,使用一些东西像 awaitility 用于获取数据等大型异步功能,但在我的情况下我应该使用什么东西没有被获取但更多的是与 UI?
交互
这是我创建的使用 Thread.Sleep():
登录测试的示例
onView(withId(R.id.fieldEmail)).perform(typeText("shelley@gmail.com"));
Thread.sleep(SHORT_WAIT);
onView(withId(R.id.fieldPassword)).perform(click());
onView(withId(R.id.fieldPassword)).perform(typeText("password"));
Thread.sleep(SHORT_WAIT);
onView(isRoot()).perform(pressBack());
Thread.sleep(SHORT_WAIT);
onView(withId(R.id.signIn)).perform(click());
Thread.sleep(LONG_WAIT);
有几种选择:
重复重试
您可以使用 Awaitility 重复重试 assertion/check,直到指定的时间允许:
app/build.gradle
dependencies {
// Note: Awaitility version 4 has dependency conflicts with JUnit's
// Hamcrest. See: https://github.com/awaitility/awaitility/issues/194
androidTestImplementation 'org.awaitility:awaitility:3.1.6'
}
// Set the retry time to 0.5 seconds, instead of the default 0.1 seconds
Awaitility.setDefaultPollInterval(500, TimeUnit.MILLISECONDS);
Kotlin:
Awaitility.await().atMost(2, TimeUnit.SECONDS).untilAsserted {
onView(withId(R.id.fieldPassword)).perform(click())
}
Java 7:
Awaitility.await().atMost(2, TimeUnit.SECONDS).untilAsserted(new ThrowingRunnable() {
@Override
public void run() throws Throwable {
onView(withId(R.id.fieldPassword)).perform(click());
}
});
这意味着如果断言第一次失败,它将重试最多 2 秒,直到 true
或直到发生超时 (fail
)。
具有初始时间延迟的重复重试
您还可以在做出第一个断言之前设置一个初始时间延迟:
Awaitility.await().pollDelay(1, TimeUnit.SECONDS).atMost(3, TimeUnit.SECONDS).untilAsserted {
onView(withId(R.id.fieldPassword)).perform(click())
}
简单的时间延迟
或者,您可以在语句之间添加简单的时间延迟,就像 Thread.sleep()
一样,但以更详细的方式:
Kotlin:
Awaitility.await().pollDelay(2, TimeUnit.SECONDS).until { true }
Java 7:
Awaitility.await().pollDelay(2, TimeUnit.SECONDS).until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return true;
}
});
使用 Espresso 或 Barista 函数创建定时等待:
- Espresso: Thread.sleep( )
使用 Espresso 空闲资源
- https://dev.to/keyopstech/robust-ui-tests-with-espresso-and-idling-resources-157f
- https://tudip.com/blog-post/espresso-idling-resources/
- https://medium.com/androiddevelopers/android-testing-with-espressos-idling-resources-and-testing-fidelity-8b8647ed57f4
- https://www.repeato.app/the-problem-of-espresso-idling-resources/(有些缺点)
一般注意事项:虽然在单元测试中通常应避免使用 Thread.sleep()
或其他一些时间延迟,但有时您需要使用它,而且别无选择。一个示例是使用 IntentsTestRule
在您的应用程序中单击 Web link 以启动外部 Web 浏览器。你不知道浏览器需要多长时间才能启动网页,所以你需要添加一个时间延迟。
有关等待时间的更多信息:
我正在使用 Espresso 为我开发的 Android 应用编写一些自动化测试。所有测试都是自动化的,并且是 passing/failing 根据 UI 发生的情况。我通过 SonarQube 运行 代码来检测错误的编码实践,它告诉我不应使用 Thread.Sleep()。
我主要在输入表单并需要隐藏键盘以向下滚动以点击下一个表单字段等的情况下使用 Thread.sleep()。根据我的理解,使用一些东西像 awaitility 用于获取数据等大型异步功能,但在我的情况下我应该使用什么东西没有被获取但更多的是与 UI?
交互这是我创建的使用 Thread.Sleep():
登录测试的示例 onView(withId(R.id.fieldEmail)).perform(typeText("shelley@gmail.com"));
Thread.sleep(SHORT_WAIT);
onView(withId(R.id.fieldPassword)).perform(click());
onView(withId(R.id.fieldPassword)).perform(typeText("password"));
Thread.sleep(SHORT_WAIT);
onView(isRoot()).perform(pressBack());
Thread.sleep(SHORT_WAIT);
onView(withId(R.id.signIn)).perform(click());
Thread.sleep(LONG_WAIT);
有几种选择:
重复重试
您可以使用 Awaitility 重复重试 assertion/check,直到指定的时间允许:
app/build.gradle
dependencies {
// Note: Awaitility version 4 has dependency conflicts with JUnit's
// Hamcrest. See: https://github.com/awaitility/awaitility/issues/194
androidTestImplementation 'org.awaitility:awaitility:3.1.6'
}
// Set the retry time to 0.5 seconds, instead of the default 0.1 seconds
Awaitility.setDefaultPollInterval(500, TimeUnit.MILLISECONDS);
Kotlin:
Awaitility.await().atMost(2, TimeUnit.SECONDS).untilAsserted {
onView(withId(R.id.fieldPassword)).perform(click())
}
Java 7:
Awaitility.await().atMost(2, TimeUnit.SECONDS).untilAsserted(new ThrowingRunnable() {
@Override
public void run() throws Throwable {
onView(withId(R.id.fieldPassword)).perform(click());
}
});
这意味着如果断言第一次失败,它将重试最多 2 秒,直到 true
或直到发生超时 (fail
)。
具有初始时间延迟的重复重试
您还可以在做出第一个断言之前设置一个初始时间延迟:
Awaitility.await().pollDelay(1, TimeUnit.SECONDS).atMost(3, TimeUnit.SECONDS).untilAsserted {
onView(withId(R.id.fieldPassword)).perform(click())
}
简单的时间延迟
或者,您可以在语句之间添加简单的时间延迟,就像 Thread.sleep()
一样,但以更详细的方式:
Kotlin:
Awaitility.await().pollDelay(2, TimeUnit.SECONDS).until { true }
Java 7:
Awaitility.await().pollDelay(2, TimeUnit.SECONDS).until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return true;
}
});
使用 Espresso 或 Barista 函数创建定时等待:
- Espresso: Thread.sleep( )
使用 Espresso 空闲资源
- https://dev.to/keyopstech/robust-ui-tests-with-espresso-and-idling-resources-157f
- https://tudip.com/blog-post/espresso-idling-resources/
- https://medium.com/androiddevelopers/android-testing-with-espressos-idling-resources-and-testing-fidelity-8b8647ed57f4
- https://www.repeato.app/the-problem-of-espresso-idling-resources/(有些缺点)
一般注意事项:虽然在单元测试中通常应避免使用 Thread.sleep()
或其他一些时间延迟,但有时您需要使用它,而且别无选择。一个示例是使用 IntentsTestRule
在您的应用程序中单击 Web link 以启动外部 Web 浏览器。你不知道浏览器需要多长时间才能启动网页,所以你需要添加一个时间延迟。
有关等待时间的更多信息: