![](/img/trans.png)
[英]ViewModel unit tests fail when run together but pass when run individually
[英]some Robolectric tests fail when run all together but pass individually
我在Android Studio 1.2,Robolectric 3.0-rc2上。
我有两个测试类,一个名为MotdTest
,一个测试方法测试POJO json序列化和反序列化。 另一个叫做UserInfoTest
,它包含4个测试方法,用于测试我在SharedPreferences
设置的用户信息。 如果我单独运行UserInfoTest
,则所有4种测试方法都会通过。 但是,如果我运行所有测试, MotdTest
的测试MotdTest
成功,但UserInfoTest
两个方法总是失败。 我现在通过调用./gradlew test
从命令行运行
当我运行所有测试时,有谁知道为什么我的一些测试失败了? 在我的UserInfoTest中,我确实有一个@After
注释的方法,我通过在SharedPreferences.Editor
上调用clear()。commit()进行清理。
UserInfoTest:
testOnSignIn()
在assertThat(6, equalTo(prefs.getAll().size()));
失败assertThat(6, equalTo(prefs.getAll().size()));
因为prefs
的大小是0。
并且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));
}
}
用户信息:
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: 这是一个修改过的版本因为我在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"));
}
}
您在PREFS
保留对SharedPreferences
静态引用。 我认为您的测试将在您在tearDown
方法中重置后立即修复,或者完全删除静态引用。 如果删除静态引用,则Robolectric
本身将清除SharedPreferences
文件 - 无需在tearDown
再次清除它。
还有一点要提 - 我也在使用Mac
,而RobolectricGradleTestRunnner
也没有任何问题。 有时我必须在运行测试之前运行clean
,但没有别的。
另外你提到了robobolectric-gradle-plugin
。 使用Android Studio v1.1 +和android gradle插件v1.1 +不需要它
使用robolectric gradle插件并设置此属性已通过我的所有测试:
robolectric {
// Specify max number of processes (default is 1)
maxParallelForks = 2
}
但是,我仍然不知道为什么这会影响我的测试,当单独运行和一起运行时。 此外,似乎不再需要robolectric gradle插件,因为我在Android Studio 1.2上,但我无法弄清楚如何在没有它的情况下让它工作并手动设置maxParallelForks属性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.