使用 Robolectric 对 ActiveAndroid 模型进行单元测试
Unit Testing ActiveAndroid Models Using Robolectric
我正在为我的一些模型使用 ActiveAndroid,我想开始对我的工作进行单元测试。不幸的是,我遇到了很多错误,即无法使用正确的上下文初始化 ActiveAndroid。
ActiveAndroid 已初始化:
ActiveAndroid.initialize(上下文)
我尝试通过以下方式初始化上下文:
有一个扩展应用程序的存根 class,并使用它来初始化数据库。
private class TestApp extends com.activeandroid.app.Application{
@Override
public void onCreate() {
super.onCreate();
initialiseDB(getDatabaseName());
}
protected String getDatabaseName() {
return "sad";
}
private void initialiseDB(String dbName) {
ActiveAndroid.initialize(this);
}
}
这失败了,因为 .getPackageName() 和 .getApplicationContext() 的 class return 为 null,这两者都由初始化在内部使用。
我也尝试过使用ShadowContextWrapper,但我可能用错了。以下是我的处理方式:
ShadowContextWrapper shadowContextWrapper = new ShadowContextWrapper();
shadowContextWrapper.setApplicationName("appName");
shadowContextWrapper.setPackageName("package");
Context context = shadowContextWrapper.getApplicationContext();
此方法失败,出现 NPE ShadowContextWrapper.java:52
Robolectric 的哪一部分。该行本身:
Context applicationContext = this.realContextWrapper.getBaseContext().getApplicationContext();
我使用的是 AS 1.2、robolectric3.0 和 activeandroid 3.1。
这是我 运行 的测试示例。
@RunWith(CustomRobolectricTestRunner.class)
public class ItemTest {
public void setUp(){
}
@Test
public void checkJUnitWork() {
assertThat(true, is(true));
}
@Test
public void testSave(){
Item item = new Item("name", "units", 5.0, 4.5, 10.0);
assertThat(item.getName(),is("name"));
}
public void tearDown(){
}
}
我自定义的Runner如下:
public class CustomRobolectricTestRunner extends RobolectricTestRunner {
public CustomRobolectricTestRunner(Class<?> testClass)
throws InitializationError {
super(testClass);
String buildVariant = (BuildConfig.FLAVOR.isEmpty()
? "" : BuildConfig.FLAVOR+ "/") + BuildConfig.BUILD_TYPE;
String intermediatesPath = BuildConfig.class.getResource("")
.toString().replace("file:", "");
intermediatesPath = intermediatesPath
.substring(0, intermediatesPath.indexOf("/classes"));
System.setProperty("android.package",
BuildConfig.APPLICATION_ID);
System.setProperty("android.manifest",
intermediatesPath + "/manifests/full/"
+ buildVariant + "/AndroidManifest.xml");
System.setProperty("android.resources",
intermediatesPath + "/res/" + buildVariant);
System.setProperty("android.assets",
intermediatesPath + "/assets/" + buildVariant);
ShadowContextWrapper shadowContextWrapper = new ShadowContextWrapper();
shadowContextWrapper.setApplicationName("appName");
shadowContextWrapper.setPackageName("package");
Context context = shadowContextWrapper.getApplicationContext();
ActiveAndroid.initialize(context);
}
}
因此,您在测试中遇到的问题是 TestApp
不是 运行ning。要获得它 运行ning,您需要将测试设置为使用指定 TestApp
作为 运行.
应用程序的清单
在源代码树的 /test
目录中按如下所示设置您的 TestApp...例如/src/test/java/some-long-package/TestApp.java
:
package com.some.company;
public class TestApp extends Application {
@Override
public void onCreate() {
super.onCreate();
ActiveAndroid.initialize(this);
}
}
这是重要的部分
在源的 /test
树中创建一个 android 清单文件。让此清单文件将 TestApp
指定为应用程序。因此,在类似于 /src/test/resources/TestManifest.xml
的路径中创建一个包含以下内容的清单:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test">
<application android:name="com.some.company.TestApp">
</application>
</manifest>
我建议摆脱 CustomRobolectricTestRunner
作为默认 Robolectric 3.0 测试 运行ner 将完成您需要完成的大部分工作。如果您需要测试各种构建变体,请使用 @RunWith(RobolectricGradleTestRunner.class)
。
但现在,请按如下方式设置您的测试:
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, manifest = "src/test/resources/TestManifest.xml", sdk = Build.VERSION_CODES.LOLLIPOP)
public class MainAppTest {
@Test
public void runtimeApplicationShouldBeTestApp() throws Exception {
String actualName = RuntimeEnvironment.application.getClass().getName();
String expectedName = TestApp.class.getName();
assert(actualName).equals(expectedName);
}
}
@Config(manifest= ...)
位将设置 Robolectric 以使用测试清单和测试应用程序。上面的简单测试验证了测试中使用的应用程序上下文确实是 TestApp.class
这将确保 ActiveAndroid 为测试正确初始化。
我也同意 Eugen 的观点,您可能会尝试在测试中做更多的事情。通过您的应用程序测试您的数据库,您实际上是在创建一个集成测试。我建议尽可能地拆分功能。
测试愉快!
我正在为我的一些模型使用 ActiveAndroid,我想开始对我的工作进行单元测试。不幸的是,我遇到了很多错误,即无法使用正确的上下文初始化 ActiveAndroid。
ActiveAndroid 已初始化:
ActiveAndroid.initialize(上下文)
我尝试通过以下方式初始化上下文:
有一个扩展应用程序的存根 class,并使用它来初始化数据库。
private class TestApp extends com.activeandroid.app.Application{ @Override public void onCreate() { super.onCreate(); initialiseDB(getDatabaseName()); } protected String getDatabaseName() { return "sad"; } private void initialiseDB(String dbName) { ActiveAndroid.initialize(this); } }
这失败了,因为 .getPackageName() 和 .getApplicationContext() 的 class return 为 null,这两者都由初始化在内部使用。
我也尝试过使用ShadowContextWrapper,但我可能用错了。以下是我的处理方式:
ShadowContextWrapper shadowContextWrapper = new ShadowContextWrapper();
shadowContextWrapper.setApplicationName("appName");
shadowContextWrapper.setPackageName("package");
Context context = shadowContextWrapper.getApplicationContext();
此方法失败,出现 NPE ShadowContextWrapper.java:52 Robolectric 的哪一部分。该行本身:
Context applicationContext = this.realContextWrapper.getBaseContext().getApplicationContext();
我使用的是 AS 1.2、robolectric3.0 和 activeandroid 3.1。
这是我 运行 的测试示例。
@RunWith(CustomRobolectricTestRunner.class)
public class ItemTest {
public void setUp(){
}
@Test
public void checkJUnitWork() {
assertThat(true, is(true));
}
@Test
public void testSave(){
Item item = new Item("name", "units", 5.0, 4.5, 10.0);
assertThat(item.getName(),is("name"));
}
public void tearDown(){
}
}
我自定义的Runner如下:
public class CustomRobolectricTestRunner extends RobolectricTestRunner {
public CustomRobolectricTestRunner(Class<?> testClass)
throws InitializationError {
super(testClass);
String buildVariant = (BuildConfig.FLAVOR.isEmpty()
? "" : BuildConfig.FLAVOR+ "/") + BuildConfig.BUILD_TYPE;
String intermediatesPath = BuildConfig.class.getResource("")
.toString().replace("file:", "");
intermediatesPath = intermediatesPath
.substring(0, intermediatesPath.indexOf("/classes"));
System.setProperty("android.package",
BuildConfig.APPLICATION_ID);
System.setProperty("android.manifest",
intermediatesPath + "/manifests/full/"
+ buildVariant + "/AndroidManifest.xml");
System.setProperty("android.resources",
intermediatesPath + "/res/" + buildVariant);
System.setProperty("android.assets",
intermediatesPath + "/assets/" + buildVariant);
ShadowContextWrapper shadowContextWrapper = new ShadowContextWrapper();
shadowContextWrapper.setApplicationName("appName");
shadowContextWrapper.setPackageName("package");
Context context = shadowContextWrapper.getApplicationContext();
ActiveAndroid.initialize(context);
}
}
因此,您在测试中遇到的问题是 TestApp
不是 运行ning。要获得它 运行ning,您需要将测试设置为使用指定 TestApp
作为 运行.
在源代码树的 /test
目录中按如下所示设置您的 TestApp...例如/src/test/java/some-long-package/TestApp.java
:
package com.some.company;
public class TestApp extends Application {
@Override
public void onCreate() {
super.onCreate();
ActiveAndroid.initialize(this);
}
}
这是重要的部分
在源的 /test
树中创建一个 android 清单文件。让此清单文件将 TestApp
指定为应用程序。因此,在类似于 /src/test/resources/TestManifest.xml
的路径中创建一个包含以下内容的清单:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test">
<application android:name="com.some.company.TestApp">
</application>
</manifest>
我建议摆脱 CustomRobolectricTestRunner
作为默认 Robolectric 3.0 测试 运行ner 将完成您需要完成的大部分工作。如果您需要测试各种构建变体,请使用 @RunWith(RobolectricGradleTestRunner.class)
。
但现在,请按如下方式设置您的测试:
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, manifest = "src/test/resources/TestManifest.xml", sdk = Build.VERSION_CODES.LOLLIPOP)
public class MainAppTest {
@Test
public void runtimeApplicationShouldBeTestApp() throws Exception {
String actualName = RuntimeEnvironment.application.getClass().getName();
String expectedName = TestApp.class.getName();
assert(actualName).equals(expectedName);
}
}
@Config(manifest= ...)
位将设置 Robolectric 以使用测试清单和测试应用程序。上面的简单测试验证了测试中使用的应用程序上下文确实是 TestApp.class
这将确保 ActiveAndroid 为测试正确初始化。
我也同意 Eugen 的观点,您可能会尝试在测试中做更多的事情。通过您的应用程序测试您的数据库,您实际上是在创建一个集成测试。我建议尽可能地拆分功能。
测试愉快!