我正在使用 Espresso 为我开发的 Android 应用程序编写一些自动化测试。所有测试都是自动化的,并且根据 UI 发生的情况来通过/失败。我已经通过 SonarQube 运行了代码来检测不良的编码实践,它告诉我不应使用 Thread.Sleep()。
我主要在输入表单并需要隐藏键盘以向下滚动以点击下一个表单字段等的情况下使用 Thread.sleep() 。根据我的理解,使用诸如等待性之类的东西是为了大异步诸如获取数据等功能,但在我的情况下,如果没有获取某些内容,但更多的是与 UI 交互,我应该使用什么?
这是我创建的使用 Thread.Sleep() 的登录测试示例:
onView(withId(R.id.fieldEmail)).perform(typeText("[email protected]"));
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 重复重试断言/检查,直到指定的时间允许:
应用程序/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'
}
import java.util.concurrent.TimeUnit;
// Set the retry time to 0.5 seconds, instead of the default 0.1 seconds
Awaitility.setDefaultPollInterval(500, TimeUnit.MILLISECONDS);
// Kotlin:
Awaitility.await().atMost(4, TimeUnit.SECONDS).untilAsserted {
onView(withId(R.id.fieldPassword)).perform(click())
}
// Java 8:
Awaitility.await().atMost(4, TimeUnit.SECONDS).untilAsserted(() ->
onView(withId(R.id.fieldPassword)).perform(click())
);
// Java 7:
Awaitility.await().atMost(4, TimeUnit.SECONDS).untilAsserted(new ThrowingRunnable() {
@Override
public void run() throws Throwable {
onView(withId(R.id.fieldPassword)).perform(click());
}
});
这意味着如果断言第一次失败,它将重试最多 2 秒,直到
true
或直到发生超时 (fail
)。
您还可以在做出第一个断言之前设置初始时间延迟:
import java.util.concurrent.TimeUnit
Awaitility
.await()
.pollInterval(500, TimeUnit.MILLISECONDS)
.pollDelay(1, TimeUnit.SECONDS)
.atMost(3, TimeUnit.SECONDS)
.untilAsserted { onView(withId(R.id.fieldPassword)).perform(click()) }
或者,您可以在语句之间添加简单的时间延迟,就像
Thread.sleep()
一样,但以更详细的方式:
import java.util.concurrent.TimeUnit;
// Kotlin:
Awaitility.await().pollDelay(2, TimeUnit.SECONDS).until { true }
// Java 8
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;
}
});
有关等待性的更多信息:
对于可组合 UI 测试,请使用
composeTestRule.waitForIdle()
和 composeTestRule.waitUntil()
。这将导致测试运行程序等待较长的操作完成。一个例子是等待屏幕键盘出现或消失。
composeTestRule.onNodeWithTag(TextInputTag.TEXT_ENTRY_FIELD).performClick()
// Wait for the on-screen keyboard to display, which can take up to 3 seconds
composeTestRule.waitForIdle()
// Assert something after the keyboard has appeared
composeTestRule.onNodeWithTag(TextInputTag.TEXT_ENTRY_FIELD).assert...()
val THREE_SECONDS_TIMEOUT = 3000L
composeTestRule.onNodeWithTag(TextInputTag.TEXT_ENTRY_FIELD).performClick()
// Wait for the user login to finish
composeTestRule.waitUntil(THREE_SECONDS_TIMEOUT) { isUserLoggedIn() }
// Assert something after the user has logged in
composeTestRule.onNodeWithTag(TextInputTag.TEXT_ENTRY_FIELD).assert...()
一般注意事项:虽然在单元测试中通常应避免使用
Thread.sleep()
或其他一些时间延迟,但有时您需要使用它,并且没有其他选择。一个示例是使用 IntentsTestRule
单击应用程序中的 Web 链接以启动外部 Web 浏览器。你不知道浏览器需要多长时间才能启动网页,所以你需要添加一个时间延迟。