【发布时间】:2013-06-17 09:59:00
【问题描述】:
继我的 Android TDD 系列中的 other questions 之后,我已经设法使用 Robolectric、Mockito、Maven 和 ABS 来对我的 Android 开发进行单元测试。显然,我似乎在突破自己的知识界限,但 Android CI 的梦想实在是太诱人了。如果您能帮助解决我的下一个问题,我将不胜感激,就在这里;
我想编写一个集成测试用例,它将我的应用程序数据库从 v1 带到 head。我正在为 DI 使用Dagger 并促进这种非标准 JUnit 测试,我将执行升级所需的类注入到我的测试中;
@RunWith(RobolectricTestRunner.class)
public class TestDatabaseHelper {
private static final String V1_DATABASE_SQL = "res/test-support/v1-database/v1-database.sql";
@Inject private UpgradeAuditService upgradeAuditService;
@Rule public StoutLoggingRule loggingRule = new StoutLoggingRule();
@Rule public DaggerInjector injector = new DaggerInjector();
/**
* Tests upgrading the database from version 1 to HEAD.
*
* @throws NameNotFoundException When there is no app but it's running the app. A WTF moment.
* @throws IOException when something goes wrong.
*/
@Test
@Config(manifest="../OceanLife/AndroidManifest.xml")
public void testUpgradingToHead() throws NameNotFoundException, IOException {
// Given.
final Context testApplicationContext = Robolectric.getShadowApplication().getApplicationContext();
final SQLiteDatabase database = SQLiteDatabase.openDatabase("/data/data/com.oceanlife/databases/oceanlife.db", null, SQLiteDatabase.OPEN_READWRITE);
final int versionCode = testApplicationContext.getPackageManager().getPackageInfo("com.oceanlife", 0).versionCode;
// When.
replaceDatabase(database);
new DatabaseHelper(testApplicationContext, upgradeAuditService).onUpgrade(database, 1, versionCode);
// Then.
final int databaseVersion = SQLiteDatabase.openDatabase("/data/data/com.oceanlife/databases/oceanlife.db", null, SQLiteDatabase.OPEN_READWRITE).getVersion();
assertEquals("Database was not upgraded.", versionCode, databaseVersion);
}
注意事项;
- 测试存在于它自己的测试项目下,独立于被测项目(有关结构,请参阅我的链接问题)
- 失败(下面的堆栈跟踪)是在创建实际应用程序的模块图时发生的。
- 注入器规则(如下所述)链接到测试项目模块,其中包括在实际运行我的应用程序时使用的模块。
DaggerInjector 规则下发生了什么?
我尝试注入测试所需的任何依赖项。
public class DaggerInjector implements MethodRule {
/**
* @see org.junit.rules.MethodRule#apply(org.junit.runners.model.Statement, org.junit.runners.model.FrameworkMethod, java.lang.Object)
*/
@Override
public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
final ObjectGraph graph = ObjectGraph.create(new OceanLifeTestingModule());
graph.inject(target);
base.evaluate();
}
};
}
}
您的测试模块是什么样的?
为测试添加入口点(这是dagger-0.9.1,而不是inject 替换entryPoints 的最新版本)用于测试和(未来)测试模拟替换。
/**
* The injection container providing information on
* how to construct test support components.
*
* @author David C Branton
*/
@Module(includes = OceanLifeModule.class,
entryPoints = {FixtureBuilder.class,
TestSpotService.class,
TestDatabaseHelper.class},
complete = true,
overrides = true)
public class OceanLifeTestingModule {
/**
* Constructs this module.
*/
public OceanLifeTestingModule() { }
/**
* Provide the database.
*
* @return the application database.
*/
@Provides SQLiteDatabase provideDatabase() {
return SQLiteDatabase.openDatabase("/data/data/com.oceanlife/databases/oceanlife.db", null, SQLiteDatabase.OPEN_READWRITE);
}
}
如果我注释掉负责创建我的真实应用程序对象图的代码行,我的测试就会运行绿色。这是堆栈跟踪;
错误 1:从我的测试角度捕捉并吞下
dagger.internal.RuntimeAggregatingPlugin#getModuleAdapter
java.lang.RuntimeException: Unexpected failure loading com.oceanlife.OceanLifeModule$ModuleAdapter
错误 2:被 Robolectric 转储到控制台
java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
at sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:653)
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:460)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:286)
at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:222)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:69)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:52)
at java.lang.Class.initAnnotationsIfNecessary(Class.java:3079)
at java.lang.Class.getAnnotation(Class.java:3038)
at dagger.internal.plugins.reflect.ReflectivePlugin.getModuleAdapter(ReflectivePlugin.java:51)
at dagger.internal.RuntimeAggregatingPlugin.getModuleAdapter(RuntimeAggregatingPlugin.java:98)
at dagger.internal.RuntimeAggregatingPlugin.getAllModuleAdapters(RuntimeAggregatingPlugin.java:55)
at dagger.ObjectGraph.makeGraph(ObjectGraph.java:115)
at dagger.ObjectGraph.create(ObjectGraph.java:103)
at com.oceanlife.MainApplication.onCreate(MainApplication.java:36)
at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:146)
at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:387)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:227)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:177)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
迄今为止的调查
我一直专注于为什么会发生“错误 1”。从阅读"Compile Time Code Generation" 方面到用户指南,我可以看到 RuntimeAggregatingPlugin 正在寻找的适配器 (OceanLifeModule$ModuleAdapter) 是在编译时生成的。从那以后,我一直在检查我的 Maven 配置,如果社区认为有必要解决这个问题,我很乐意提供。 “错误 2”的低级性质使我认为它比根本原因更具衍生性。
【问题讨论】:
标签: android integration-testing junit4 android-maven-plugin dagger