简体   繁体   English

一些Robolectric测试在一起运行时失败但是单独通过

[英]some Robolectric tests fail when run all together but pass individually

I'm on Android Studio 1.2, Robolectric 3.0-rc2. 我在Android Studio 1.2,Robolectric 3.0-rc2上。

I have two test classes, one called MotdTest with one test method that tests for POJO json serialization & deserialization. 我有两个测试类,一个名为MotdTest ,一个测试方法测试POJO json序列化和反序列化。 The other is called UserInfoTest , which contains 4 test methods that tests for user info that I set into SharedPreferences . 另一个叫做UserInfoTest ,它包含4个测试方法,用于测试我在SharedPreferences设置的用户信息。 If I run UserInfoTest individually, all 4 test methods always pass. 如果我单独运行UserInfoTest ,则所有4种测试方法都会通过。 However, if I run all the tests, the test in MotdTest succeeds, but two methods of UserInfoTest always fails. 但是,如果我运行所有测试, MotdTest的测试MotdTest成功,但UserInfoTest两个方法总是失败。 I'm running from command line right now by calling ./gradlew test 我现在通过调用./gradlew test从命令行运行

Does anyone know why some of my tests are failing when I run all tests? 当我运行所有测试时,有谁知道为什么我的一些测试失败了? In my UserInfoTest I do properly have an @After annotated method where I do cleanup by calling clear().commit() on the SharedPreferences.Editor . 在我的UserInfoTest中,我确实有一个@After注释的方法,我通过在SharedPreferences.Editor上调用clear()。commit()进行清理。

UserInfoTest: UserInfoTest:

testOnSignIn() fails at assertThat(6, equalTo(prefs.getAll().size())); testOnSignIn()assertThat(6, equalTo(prefs.getAll().size()));失败assertThat(6, equalTo(prefs.getAll().size())); because the size of prefs is 0. 因为prefs的大小是0。

And testIsSignedIn() fails at assertThat(UserInfo.isSignedIn(), is(false)); 并且testIsSignedIn()assertThat(UserInfo.isSignedIn(), is(false));失败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));
    }
}

UserInfo: 用户信息:

App is an Application subclass and App.getInstance() is a singleton. App是一个Application子类, 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: A modified version of this because I'm on mac, and also because I'm targeting API 22 in my project, but robolectric doesn't support up to that yet, so I run my tests against API 21. MyRoboRunner: 是一个修改过的版本因为我在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"));
    }
}

You keep static references to SharedPreferences in the PREFS . 您在PREFS保留对SharedPreferences静态引用。 I think your tests will be fixed as soon as you reset it in your tearDown method or remove static references at all. 我认为您的测试将在您在tearDown方法中重置后立即修复,或者完全删除静态引用。 If you remove static reference then SharedPreferences file will be cleared by Robolectric itself - no need to clear it again in tearDown . 如果删除静态引用,则Robolectric本身将清除SharedPreferences文件 - 无需在tearDown再次清除它。

Another point to mention - I'm also using Mac and I don't have any issue with RobolectricGradleTestRunnner . 还有一点要提 - 我也在使用Mac ,而RobolectricGradleTestRunnner也没有任何问题。 Sometimes I have to run clean before running the tests but nothing else. 有时我必须在运行测试之前运行clean ,但没有别的。

And another thing that you mentioned robobolectric-gradle-plugin . 另外你提到了robobolectric-gradle-plugin You don't need it with Android Studio v1.1+ and android gradle plugin v1.1+ 使用Android Studio v1.1 +和android gradle插件v1.1 +不需要它

Using the robolectric gradle plugin and setting this property has all my tests passing: 使用robolectric gradle插件并设置此属性已通过我的所有测试:

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

But, I still don't know why this would affect my tests when run individually vs all together. 但是,我仍然不知道为什么这会影响我的测试,当单独运行和一起运行时。 Also, it seems that the robolectric gradle plugin isn't necessary anymore since I'm on Android Studio 1.2, but I couldn't figure out how to get it to work without it and setting the maxParallelForks property manually. 此外,似乎不再需要robolectric gradle插件,因为我在Android Studio 1.2上,但我无法弄清楚如何在没有它的情况下让它工作并手动设置maxParallelForks属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM