在 InstrumentationTestCase 运行之间重置应用程序状态

Reset app state between InstrumentationTestCase runs

我的一位 QA 工程师正在支持一个具有相当大的代码库和许多不同的 SharedPreferences 文件的应用程序。前几天他来找我询问如何在测试运行之间重置应用程序状态,就好像它已被卸载-重新安装一样。

Espresso(他正在使用)和 Android 测试框架本身都不支持,所以我不确定该告诉他什么。使用本机方法来清除所有不同的 SharedPreferences 文件将是一个非常脆弱的解决方案。

如何在检测期间重置应用程序状态?

当前的 espresso 不提供任何重置应用程序状态的机制。但是对于每个方面(pref、db、文件、权限)都存在一个解决方案。

一开始你必须避免浓缩咖啡自动启动你的 activity 这样你就有足够的时间重新设置。

@Rule
public ActivityTestRule<Activity> activityTestRule = new ActivityTestRule<>(Activity.class, false, false);

然后用

开始你的 activity
activityTestRule.launchActivity(null)

要重置首选项,您可以使用以下代码段(在开始 activity 之前)

File root = InstrumentationRegistry.getTargetContext().getFilesDir().getParentFile();
String[] sharedPreferencesFileNames = new File(root, "shared_prefs").list();
for (String fileName : sharedPreferencesFileNames) {
    InstrumentationRegistry.getTargetContext().getSharedPreferences(fileName.replace(".xml", ""), Context.MODE_PRIVATE).edit().clear().commit();
}

您也可以在启动 activity 后重置首选项。但是 activity 可能已经阅读了首选项。

您的应用程序 class 只启动了一次,并且在您可以重置首选项之前已经启动。

我已经开始编写一个库,它应该使使用 espresso 和 uiautomator 的测试更加简单。这包括用于重置应用程序数据的工具。 https://github.com/nenick/espresso-macchiato 例如,请参阅 EspAppDataTool 以及清除首选项、数据库、缓存文件和存储文件的方法。

改进@nenick 的解决方案,将状态清除行为封装在自定义 ActivityTestRule 中。如果这样做,您可以允许测试继续自动启动 activity 而无需您的干预。对于自定义 ActivityTestRule,activity 在启动测试时已经处于所需状态。

规则特别有用,因为它们不依赖于任何特定测试 class,因此可以在任何测试 class 或任何项目中轻松重复使用。

下面是我实施的一个,以确保在每个测试 activity 启动时应用程序已注销。一些测试在失败时会使应用程序处于登录状态。这会导致后面的测试也失败,因为后面的测试假设他们需要登录,但应用程序已经登录了。

public class SignedOutActivityTestRule<T extends Activity> extends ActivityTestRule<T> {

    public SignedOutActivityTestRule(Class<T> activityClass) {
        super(activityClass);
    }

    @Override
    protected void beforeActivityLaunched() {
        super.beforeActivityLaunched();
        InstrumentationRegistry.getTargetContext()
                .getSharedPreferences(
                        Authentication.SHARED_PREFERENCES_NAME,
                        Context.MODE_PRIVATE)
                .edit()
                .remove(Authentication.KEY_SECRET)
                .remove(Authentication.KEY_USER_ID)
                .apply();
    }

}

您可以尝试将此添加到 gradle:

android {
...
defaultConfig {
...
    testInstrumentationRunnerArguments clearPackageData: 'true'
   }
}

参考https://developer.android.com/training/testing/junit-runner

要在每次测试后从设备的 CPU 和内存中删除所有共享状态,请使用 clearPackageData 标志。