【问题标题】:some Robolectric tests fail when run all together but pass individually一些 Robolectric 测试在一起运行但单独通过时失败
【发布时间】:2015-07-15 16:40:45
【问题描述】:

我使用的是 Android Studio 1.2,Robolectric 3.0-rc2。

我有两个测试类,一个称为MotdTest,其中一个测试方法用于测试 POJO json 序列化和反序列化。另一个叫做UserInfoTest,它包含4个测试方法来测试我在SharedPreferences中设置的用户信息。如果我单独运行UserInfoTest,所有 4 种测试方法总是通过。但是,如果我运行所有测试,MotdTest 中的测试成功,但UserInfoTest 的两种方法总是失败。我现在通过调用./gradlew test从命令行运行@

有谁知道为什么我运行所有测试时我的一些测试都失败了?在我的 UserInfoTest 中,我确实有一个 @After 注释方法,我通过在 SharedPreferences.Editor 上调用 clear().commit() 来进行清理。

用户信息测试:

testOnSignIn()assertThat(6, equalTo(prefs.getAll().size())); 处失败,因为 prefs 的大小为 0。

testIsSignedIn()assertThat(UserInfo.isSignedIn(), is(false)); 失败

@RunWith(MyRoboRunner.class)
@Config(constants = BuildConfig.class)
public class UserInfoTest {

    private String mExpectedId;

    private String mExpectedName;

    private String mExpectedEmail;

    private String mExpectedToken;

    private String mExpectedKey;

    @Before
    public void setUp() throws Exception {
        ShadowLog.stream = System.out;

        mExpectedId = "someiD";
        mExpectedName = "johnny boy";
        mExpectedEmail = "some@email.com";
        mExpectedToken = "Session Token";
        mExpectedKey = "Session Key";
    }

    @After
    public void tearDown() {
        SharedPreferences prefs = RuntimeEnvironment.application.getSharedPreferences(
                UserInfo.PREFERENCES, Context.MODE_PRIVATE);
        prefs.edit().clear().commit();
        mExpectedId = null;
        mExpectedName = null;
        mExpectedEmail = null;
        mExpectedToken = null;
        mExpectedKey = null;
    }

    @Test
    public void testOnSignIn() {        
        SharedPreferences prefs = RuntimeEnvironment.application.getSharedPreferences(
                UserInfo.PREFERENCES, Context.MODE_PRIVATE);

        UserInfo.onSignIn(mExpectedId, mExpectedName, mExpectedEmail, mExpectedKey, mExpectedToken);
        assertThat(mExpectedKey, equalTo(UserInfo.getSessionKey()));

        assertThat(mExpectedToken, equalTo(UserInfo.getSessionToken()));
        assertThat(mExpectedId, equalTo(UserInfo.getUserId()));
        assertThat(mExpectedEmail, equalTo(UserInfo.getUserEmail()));
        assertThat(mExpectedName, equalTo(UserInfo.getUserName()));

        assertThat(6, equalTo(prefs.getAll().size()));
    }

    @Test
    public void testOnSignOut() {
        UserInfo.onSignIn(mExpectedId, mExpectedName, mExpectedEmail, mExpectedKey, mExpectedToken);
        // Set Over21 to make sure we unset this value on Signout
        UserInfo.setIsOver21(true);

        UserInfo.onSignOut();
        SharedPreferences prefs = RuntimeEnvironment.application.getSharedPreferences(
                UserInfo.PREFERENCES, Context.MODE_PRIVATE);
        assertThat(UserInfo.getSessionKey(), nullValue());
        assertThat(UserInfo.getSessionToken(), nullValue());
        assertThat(UserInfo.isOver21Set(), is(false));
        assertThat(prefs.getAll().size(), equalTo(0));
    }

    @Test
    public void testIsSignedIn() {
        assertThat(UserInfo.isSignedIn(), is(false));

        UserInfo.onSignIn(mExpectedId, mExpectedName, mExpectedEmail, mExpectedKey, mExpectedToken);
        assertThat(UserInfo.isSignedIn(), is(true));

        UserInfo.onSignOut();
        assertThat(UserInfo.isSignedIn(), is(false));
    }

    @Test
    public void testIsOver21Set() {
        assertThat(UserInfo.isOver21Set(), is(false));
        UserInfo.setIsOver21(false);
        assertThat(UserInfo.isOver21Set(), is(true));
    }
}

用户信息:

AppApplication 子类,App.getInstance() 是单例。

private static final SharedPreferences PREFS = App.getInstance()
        .getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);

public static void onSignIn(String userId, String fullName, String email, String sessionKey,
        String sessionToken) {
    SharedPreferences.Editor editor = PREFS.edit();
    editor.putString(PROPERTY_USER_ID, userId);
    editor.putString(PROPERTY_USER_NAME, fullName);
    editor.putString(PROPERTY_USER_EMAIL, email);
    editor.putString(PROPERTY_SESSION_KEY, sessionKey);
    editor.putString(PROPERTY_SESSION_TOKEN, sessionToken);
    editor.putStringSet(PROPERTY_PENDING_SCANS, new HashSet<String>());

    editor.commit();
}
public static boolean isSignedIn() {
    return getSessionToken() != null;
}

MyRoboRunner:this 的修改版本,因为我在 mac 上,还因为我在项目中针对 API 22,但 robolectric 还不支持,所以我针对 API 运行测试21.

public class MyRoboRunner extends RobolectricGradleTestRunner {

    public MyRoboRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }

    protected AndroidManifest getAppManifest(Config config) {
        AndroidManifest appManifest = super.getAppManifest(config);
        String moduleRoot = getModuleRootPath(config);

        //can use this line instead dynamic path resolution when AS bug is fix, or use @Config
        //FsFile androidManifestFile = appManifest.getAndroidManifestFile();
        FsFile androidManifestFile = FileFsFile.from(moduleRoot,
                appManifest.getAndroidManifestFile().getPath()
                        .replace("bundles", "manifests/full"));
        FsFile resDirectory = FileFsFile.from(moduleRoot, appManifest.getResDirectory().getPath());
        FsFile assetsDirectory = FileFsFile
                .from(moduleRoot, appManifest.getAssetsDirectory().getPath());
        return new AndroidManifest(androidManifestFile, resDirectory, assetsDirectory) {
            @Override
            public int getTargetSdkVersion() {
                //lollipop bc it's highest that robolectric 3.0 supports
                return Build.VERSION_CODES.LOLLIPOP;
            }

            @Override
            public int getMinSdkVersion() {
                return Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1;
            }
        };
    }

    private String getModuleRootPath(Config config) {
        String moduleRoot = config.constants().getResource("").toString().replace("file:", "");
        return moduleRoot.substring(0, moduleRoot.indexOf("/build"));
    }
}

【问题讨论】:

  • 你看到什么样的失败?可以分享一下测试代码吗?
  • @EugenMartynov 我已经包含了一些我用于测试的代码。

标签: android robolectric robolectric-gradle-plugin


【解决方案1】:

您在PREFS 中保留对SharedPreferences 的静态引用。我认为只要您在 tearDown 方法中重置它或完全删除静态引用,您的测试就会得到修复。如果您删除静态引用,则SharedPreferences 文件将被Robolectric 本身清除 - 无需在tearDown 中再次清除它。

还有一点要提——我也在使用Mac,我对RobolectricGradleTestRunnner 没有任何问题。有时我必须在运行测试之前运行clean,但仅此而已。

还有你提到的另一件事robobolectric-gradle-plugin。 Android Studio v1.1+ 和 android gradle plugin v1.1+ 不需要它

【讨论】:

    【解决方案2】:

    使用robolectric gradle plugin 并设置此属性使我的所有测试都通过了:

    robolectric {
        // Specify max number of processes (default is 1)
        maxParallelForks = 2
    }
    

    但是,我仍然不知道为什么这会影响我单独运行和一起运行的测试。此外,似乎不再需要 robolectric gradle 插件,因为我使用的是 Android Studio 1.2,但我无法弄清楚如何在没有它的情况下让它工作并手动设置 maxParallelForks 属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多