这是我到目前为止设置的:
生产
在app / src / main / java / com / mypackage / injection下我有:
MyCustomApplication
package com.mypackage.injection; import android.app.Application; import java.util.ArrayList; import java.util.List; import dagger.ObjectGraph; public class MyCustomApplication extends Application { protected ObjectGraph graph; @Override public void onCreate() { super.onCreate(); graph = ObjectGraph.create(getModules().toArray()); } protected List<Object> getModules() { List<Object> modules = new ArrayList<Object>(); modules.add(new AndroidModule(this)); modules.add(new RemoteResourcesModule(this)); modules.add(new MyCustomModule()); return modules; } public void inject(Object object) { graph.inject(object); } }
我以下列方式使用:
BaseActivity
package com.mypackage.injection.views; import android.app.Activity; import android.os.Bundle; import com.mypackage.injection.MyCustomApplication; public abstract class MyCustomBaseActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ((MyCustomApplication)getApplication()).inject(this); } }
被测活动
package com.mypackage.views.mydomain; // imports snipped for bevity public class MyActivity extends MyBaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //snip } }
浓咖啡设置
在app / src / androidTest / java / com / mypackage / injection下我有:
MyCustomEspressoApplication
package com.mypackage.injection; import java.util.ArrayList; import java.util.List; import dagger.ObjectGraph; public class MyCustomEspressoApplication extends MyCustomApplication { private AndroidModule androidModule; private MyCustomModule myCustomModule; private EspressoRemoteResourcesModule espressoRemoteResourcesModule; @Override public void onCreate() { super.onCreate(); graph = ObjectGraph.create(getModules().toArray()); } protected List<Object> getModules() { List<Object> modules = new ArrayList<Object>(); modules.add(getAndroidModule()); modules.add(getEspressoRemoteResourcesModule()); modules.add(getMyCustomModule()); return modules; } public void inject(Object object) { graph.inject(object); } public AndroidModule getAndroidModule() { if (this.androidModule == null) { this.androidModule = new AndroidModule(this); } return this.androidModule; } public MyCustomModule getMyCustomModule() { if (this.myCustomModule == null) { this.myCustomModule = new MyCustomModule(); } return this.myCustomModule; } public EspressoRemoteResourcesModule getEspressoRemoteResourcesModule() { if (this.espressoRemoteResourcesModule == null) { this.espressoRemoteResourcesModule = new EspressoRemoteResourcesModule(); } return this.espressoRemoteResourcesModule; } }
我的Espresso测试,在app / src / androidTest / com / mypackage / espresso下:
package com.mypackage.espresso; // imports snipped for brevity @RunWith(AndroidJUnit4.class) @LargeTest public class MyActivityTest extends ActivityInstrumentationTestCase2<MyActivity>{ private MyActivity myActivity; public MyActivityTest() { super(MyActivity.class); } @Before public void setUp() throws Exception { super.setUp(); injectInstrumentation(InstrumentationRegistry.getInstrumentation()); myActivity = getActivity(); } @After public void tearDown() throws Exception { super.tearDown(); } @Test public void testWhenTheActionBarButtonIsPressedThenThePlacesAreListed() { //The next line is where the runtime exception occurs. MyCustomEspressoApplication app = (MyCustomEspressoApplication)getInstrumentation().getTargetContext().getApplicationContext(); //I've also tried getActivity().getApplication() and // getActivity.getApplicationContext() with the same results //snip } }
我的AndroidManifest.xml
(我以前在自定义应用程序类中看到关于ClassCastException的许多答案,其中大部分都是在Application节点上指出一个缺少的“android:name”属性,我把这个粘贴在这里表明不是这样的据我所知.)
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.mypackage"> <!-- snip --> <application android:name=".injection.MyCustomApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <!-- snip --> </application> <!-- snip --> </manifest>
的build.gradle
buildscript { repositories { mavenCentral() jcenter() } } apply plugin: 'com.android.application' apply plugin: 'idea' android { testOptions { unitTests.returnDefaultValues = true } lintOptions { abortOnError false } packagingOptions { exclude 'LICENSE.txt' exclude 'Meta-INF/LICENSE' exclude 'Meta-INF/LICENSE.txt' exclude 'Meta-INF/NOTICE' } compileSdkVersion 21 buildToolsVersion "21.1.2" defaultConfig { applicationId "com.mypackage" minSdkVersion 15 targetSdkVersion 21 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } } idea { module { testOutputDir = file('build/test-classes/debug') } } dependencies { compile project(':swipeablecardview') compile fileTree(dir: 'libs',include: ['*.jar']) compile 'com.android.support:support-annotations:21.0.3' compile 'com.android.support:appcompat-v7:21.0.3' compile 'com.squareup:javawriter:2.5.0' compile ('com.squareup.dagger:dagger:1.2.2') { exclude module: 'javawriter' } compile ('com.squareup.dagger:dagger-compiler:1.2.2') { exclude module: 'javawriter' } compile 'com.melnykov:floatingactionbutton:1.1.0' compile 'com.android.support:cardview-v7:21.0.+' compile 'com.android.support:recyclerview-v7:21.0.+' // compile 'se.walkercrou:google-places-api-java:2.1.0' compile 'org.apache.httpcomponents:httpclient-android:4.3.5.1' compile 'commons-io:commons-io:1.3.2' testCompile 'org.hamcrest:hamcrest-integration:1.3' testCompile 'org.hamcrest:hamcrest-core:1.3' testCompile 'org.hamcrest:hamcrest-library:1.3' testCompile('junit:junit:4.12') testCompile 'org.mockito:mockito-core:1.+' testCompile('org.robolectric:robolectric:3.0-SNAPSHOT') testCompile('org.robolectric:shadows-support-v4:3.0-SNAPSHOT') androidTestCompile 'org.mockito:mockito-core:1.+' androidTestCompile('com.android.support.test.espresso:espresso-core:2.0') { exclude group: 'javax.inject' exclude module: 'javawriter' } androidTestCompile('com.android.support.test:testing-support-lib:0.1') }
堆栈跟踪:
java.lang.ClassCastException:
com.mypackage.injection.MyCustomApplication cannot be cast to
com.mypackage.injection.MyCustomEspressoApplication at
com.mypackage.espresso.MyActivityTest.testWhenTheActionBarButtonIsPressedThenThePlacesAreListed(MyActivityTest.java:107)
at java.lang.reflect.Method.invokeNative(Native Method) at
java.lang.reflect.Method.invoke(Method.java:511) at
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at
org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at
org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at
org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at
org.junit.runners.ParentRunner.run(ParentRunner.java:300) at
org.junit.runners.Suite.runChild(Suite.java:128) at
org.junit.runners.Suite.runChild(Suite.java:24) at
org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at
org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at
org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at
org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at
org.junit.runners.ParentRunner.run(ParentRunner.java:300) at
org.junit.runner.JUnitCore.run(JUnitCore.java:157) at
org.junit.runner.JUnitCore.run(JUnitCore.java:136) at
android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:270)
at
android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1551)
我已经阅读了Espresso和Dagger文档,并通过Github上的问题搜索无效.我很乐意任何人都可以提供任何帮助.提前致谢.
编辑#1
我遵循Daniel的建议来扩展测试运行器并检查VerifyError,并获得以下堆栈跟踪:
java.lang.ExceptionInInitializerError at org.mockito.internal.creation.cglib.ClassImposterizer.createProxyClass(ClassImposterizer.java:95) at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:57) at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49) at org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24) at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33) at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59) at org.mockito.Mockito.mock(Mockito.java:1285) at org.mockito.Mockito.mock(Mockito.java:1163) at com.mypackage.injection.EspressoRemoteResourcesModule.<init>(EspressoRemoteResourcesModule.java:17) at com.mypackage.injection.MyCustomEspressoApplication.getEspressoRemoteResourcesModule(MyCustomEspressoApplication.java:52) at com.mypackage.injection.MyCustomEspressoApplication.getModules(MyCustomEspressoApplication.java:24) at com.mypackage.injection.MyCustomApplication.onCreate(MyCustomApplication.java:18) at com.mypackage.injection.MyCustomEspressoApplication.onCreate(MyCustomEspressoApplication.java:16) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:999) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4151) at android.app.ActivityThread.access$1300(ActivityThread.java:130) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1255) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4745) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.VerifyError: org/mockito/cglib/core/ReflectUtils at org.mockito.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:167) at org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217) at org.mockito.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145) at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:117) at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:109) at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:105) at org.mockito.cglib.proxy.Enhancer.<clinit>(Enhancer.java:70) at org.mockito.internal.creation.cglib.ClassImposterizer.createProxyClass(ClassImposterizer.java:95) at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:57) at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49) at org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24) at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33) at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59) at org.mockito.Mockito.mock(Mockito.java:1285) at org.mockito.Mockito.mock(Mockito.java:1163) at com.mypackage.injection.EspressoRemoteResourcesModule.<init>(EspressoRemoteResourcesModule.java:17) at com.mypackage.injection.MyCustomEspressoApplication.getEspressoRemoteResourcesModule(MyCustomEspressoApplication.java:52) at com.mypackage.injection.MyCustomEspressoApplication.getModules(MyCustomEspressoApplication.java:24) at com.mypackage.injection.MyCustomApplication.onCreate(MyCustomApplication.java:18) at com.mypackage.injection.MyCustomEspressoApplication.onCreate(MyCustomEspressoApplication.java:16) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:999) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4151) at android.app.ActivityThread.access$1300(ActivityThread.java:130) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1255) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4745) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method) 04-29 06:40:28.594 1016-1016/? W/ActivityManager﹕ Error in app com.mypackage running instrumentation ComponentInfo{com.mypackage.test/com.mypackage.EspressoTestRunner}: 04-29 06:40:28.594 1016-1016/? W/ActivityManager﹕ java.lang.VerifyError 04-29 06:40:28.594 1016-1016/? W/ActivityManager﹕ java.lang.VerifyError: org/mockito/cglib/core/ReflectUtils
这让我指着Mockito.我缺少必要的mockito和dexmaker图书馆.
我更新了我的依赖关系:
androidTestCompile 'org.mockito:mockito-core:1.10.19' androidTestCompile 'com.google.dexmaker:dexmaker:1.2' androidTestCompile ('com.google.dexmaker:dexmaker-mockito:1.2') { exclude module: 'hamcrest-core' exclude module: 'mockito-core' } androidTestCompile('com.android.support.test.espresso:espresso-core:2.0') { exclude group: 'javax.inject' }
我也覆盖了MyCustomModule,它需要包含EspressoRemoteResourcesModule.一旦我这样做,事情就开始工作了.
解决方法
public class MyRunner extends AndroidJUnitRunner { @Override public Application newApplication(ClassLoader cl,String className,Context context) throws Exception { return super.newApplication(cl,MyCustomEspressoApplication.class.getName(),context); } }