我正试图在Android的Robolectric测试中注入一个Mockito mock。这是我的代码
public class RoboGradleTestRunner extends RobolectricTestRunner {
public RoboGradleTestRunner(Class<?> testClass) throws InitializationError {
super(testClass);
}
@Override
protected Class<? extends TestLifecycle> getTestLifecycleClass() {
return TestLifeCycleWithInjection.class;
}
@Override
protected AndroidManifest getAppManifest(Config config) {
String manifestProperty = System.getProperty("android.manifest");
if (config.manifest().equals(Config.DEFAULT) && manifestProperty != null) {
String resProperty = System.getProperty("android.resources");
String assetsProperty = System.getProperty("android.assets");
return new AndroidManifest(Fs.fileFromPath(manifestProperty),
Fs.fileFromPath(resProperty),
Fs.fileFromPath(assetsProperty));
}
return super.getAppManifest(config);
}
public static class TestLifeCycleWithInjection extends DefaultTestLifecycle {
@Override
public void prepareTest(Object test) {
super.prepareTest(test);
TestApplication application = (TestApplication) Robolectric.application;
MockitoAnnotations.initMocks(test);
Injector.inject(test);
}
}
}
@RunWith(RoboGradleTestRunner.class)
public class SomeTest {
@Before
public void setUp() {
injectMocks(this);
}
@Inject
MyModel myModel;
@Test
public void testThatICanInject() {
JsonObject params = new JsonObject();
verify(apiClient).request(Request.Method.POST,
"/oauth/token.json",
params);
myModel.login(params);
}
}
@Module(injects = { SomeTest.class },
includes = { RootModule.class },
overrides = true
)
public class TestModule {
@Provides @Singleton
public ApiClient provideApiClient(final Context context) {
return mock(ApiClient.class);
}
}
@Module(
library = true,
complete = false,
injects = {
MainActivity.class,
}
)
public class RealModule {
...
@Provides @Singleton
ApiClient provideApiClient(final Context context) {
return new ApiClient(context);
}
}
public class TestApplication extends RealApplication {
private Object getRealModule() {
return new TestModule();
}
@Override
protected ArrayList<Object> getModules() {
ArrayList<Object> modules = super.getModules();
modules.add(new TestModule());
return modules;
}
public static <T> T injectMocks(T object) {
TestApplication app = (TestApplication) Robolectric.application;
return app.inject(object);
}
}
public class RealApplication extends Application {
private Object getRealModule() {
return new RealModule();
}
public static RealApplication from(Context context) {
return (RealApplication) context.getApplicationContext();
}
ObjectGraph objectGraph;
@Override
public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.create(getModules().toArray());
}
public <T> T inject(T object) {
return objectGraph.inject(object);
}
protected List<Object> getModules() {
List<Object> modules = new ArrayList<Object>(1);
modules.add(new RealModule());
return modules;
}
private static RealApplication instance;
}
buildscript {
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.7.+'
classpath 'com.squareup.gradle:gradle-android-test-plugin:0.9.1-SNAPSHOT'
}
}
allprojects {
repositories {
mavenCentral()
}
}
apply plugin: 'android'
repositories {
maven { url 'http://download.crashlytics.com/maven' }
}
android {
compileSdkVersion 19
buildToolsVersion "19.0.3"
defaultConfig {
minSdkVersion 14
targetSdkVersion 19
versionCode 3
versionName "1.0.2"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
buildTypes {
debug {
debuggable true
runProguard false
}
}
}
apply plugin: 'android-test'
dependencies {
repositories {
mavenCentral()
}
compile 'com.android.support:support-v4:+'
compile 'com.android.support:appcompat-v7:+'
testCompile 'junit:junit:4.11'
testCompile 'org.robolectric:robolectric:2.2'
testCompile 'org.mockito:mockito-all:1.9.5'
compile 'com.google.code.gson:gson:2.2.+'
compile 'com.google.guava:guava:16.0.+'
compile 'joda-time:joda-time:2.3'
compile 'com.netflix.rxjava:rxjava-core:+'
compile 'com.netflix.rxjava:rxjava-android:+'
compile 'com.squareup.dagger:dagger-compiler:1.2.+'
compile 'com.squareup.dagger:dagger:1.2.+'
compile 'com.jakewharton:butterknife:4.0.+'
compile 'com.github.flavienlaurent.datetimepicker:library:+'
compile 'se.emilsjolander:stickylistheaders:+'
compile project(':modules:volley')
compile project(':modules:facebook:facebook')
compile 'com.crashlytics.android:crashlytics:1.+'
compile fileTree(dir: 'libs', include: '*.jar')
}
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':project:compileTestDebugJava'.
> java.lang.NullPointerException
* Try:
Run with --info or --debug option to get more log output.
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':project:compileTestDebugJava'.
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:289)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$1.run(DefaultTaskPlanExecutor.java:33)
at org.gradle.internal.Factories$1.create(Factories.java:22)
at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:198)
at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:266)
at org.gradle.cache.internal.DefaultPersistentDirectoryStore.longRunningOperation(DefaultPersistentDirectoryStore.java:135)
at org.gradle.api.internal.changedetection.state.DefaultTaskArtifactStateCacheAccess.longRunningOperation(DefaultTaskArtifactStateCacheAccess.java:95)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:31)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:86)
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:67)
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:54)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:166)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:113)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:81)
at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:64)
at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:35)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:50)
at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:171)
at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:201)
at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:174)
at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:170)
at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:139)
at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
at org.gradle.launcher.Main.doAction(Main.java:46)
at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
at org.gradle.launcher.Main.main(Main.java:37)
at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:50)
at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:32)
at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
at org.gradle.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:33)
at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:130)
at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:48)
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
at com.sun.tools.javac.main.Main.compile(Main.java:469)
at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:132)
at org.gradle.api.internal.tasks.compile.jdk6.Jdk6JavaCompiler.execute(Jdk6JavaCompiler.java:45)
at org.gradle.api.internal.tasks.compile.jdk6.Jdk6JavaCompiler.execute(Jdk6JavaCompiler.java:38)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:96)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:49)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:35)
at org.gradle.api.internal.tasks.compile.DelegatingJavaCompiler.execute(DelegatingJavaCompiler.java:29)
at org.gradle.api.internal.tasks.compile.DelegatingJavaCompiler.execute(DelegatingJavaCompiler.java:20)
at org.gradle.api.internal.tasks.compile.IncrementalJavaCompilerSupport.execute(IncrementalJavaCompilerSupport.java:33)
at org.gradle.api.internal.tasks.compile.IncrementalJavaCompilerSupport.execute(IncrementalJavaCompilerSupport.java:24)
at org.gradle.api.tasks.compile.Compile.compile(Compile.java:67)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:219)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:212)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:201)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:533)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:516)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
... 52 more
Caused by: java.lang.NullPointerException
at dagger.internal.codegen.ModuleAdapterProcessor.checkForMultibindings(ModuleAdapterProcessor.java:400)
at dagger.internal.codegen.ModuleAdapterProcessor.generateModuleAdapter(ModuleAdapterProcessor.java:254)
at dagger.internal.codegen.ModuleAdapterProcessor.process(ModuleAdapterProcessor.java:112)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:793)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:722)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1700(JavacProcessingEnvironment.java:97)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1029)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1163)
at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1108)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:824)
at com.sun.tools.javac.main.Main.compile(Main.java:439)
... 71 more
BUILD FAILED
我终于说了算了,然后回到Robolectric 2.1,使用了Jake Wharton版本的插件。效果好多了。如果需要,请询问我详细信息。