Sto provando a configurare Dagger nei test di strumentazione Espresso per prendere in giro le chiamate a risorse esterne (servizi RESTful in questo caso). Lo schema che ho seguito in Robolectric per il mio test unitario è stato quello di estendere la mia classe Application di produzione e sostituire i moduli di Dagger con i moduli di test che restituiranno i mock. Sto tentando di fare la stessa cosa qui, ma ricevo una ClassCastException nei miei test dell'Espresso quando tento di trasmettere l'applicazione alla mia applicazione personalizzata.Posso estendere un'applicazione personalizzata in Espresso?
Ecco il mio istituito finora:
Produzione
Sotto app/src// java/com/mypackage/iniezione principale che ho:
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);
}
}
Quale utilizzo nel modo seguente:
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);
}
}
attività in prova
package com.mypackage.views.mydomain;
// imports snipped for bevity
public class MyActivity extends MyBaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//snip
}
}
Espresso Setup
Sotto app/src/androidTest/java/com/mypackage/iniezione che ho:
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;
}
}
La mia prova Espresso, sotto 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
}
}
mio AndroidManifest.xml
(ho visto molte risposte riguardanti ClassCastException nelle classi di applicazioni personalizzate e molte di esse indicano una proprietà "android: name" mancante sul nodo Application. Sto incollando questo qui per dimostrare che questo non è il caso, per quanto posso dire)
<?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')
}
Lo stacktrace:.
java.lang.ClassCastException: com.mypackage.injection.MyCustomApplication non può essere trasmesso a com.mypackage.injection.MyCustomEspressoApplication a com.mypackage.espresso.MyActivityTest.testWhenTheActionBarButtonIsPressedThenThePlacesAreListed (MyActivityTest.java:107) a java.lang.reflect.Method.invokeNative (metodo natale) a java.lang.reflect.Method.invoke (Method.java:511) a org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall (FrameworkMethod.java:45) a org.junit.internal.runners.model.ReflectiveCallable.run (ReflectiveCallable.java:15) a org.junit.runners.model.FrameworkMethod.invokeExplosively (FrameworkMethod.java: 42) a org.junit.internal.runners.statements.InvokeMethod.evaluate (InvokeMethod.java:20) a org.junit.internal.runners.statements.RunBefores.evaluate (RunBefores.java:28) a org.junit.internal.runners.statements.RunAfters.evaluate (RunAfters.java:30) a org.junit.runners.ParentRunner.runLeaf (ParentRunner.java:263) a org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:68) a org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:47) a org.junit.runners.ParentRunner $ 3.run (ParentRunner.java:231) a org.junit.runners.ParentRunner $ 1.schedule (ParentRunner.java:60) a org.junit.runners.ParentRunner.runChildren (ParentRunner.java:229) a org.junit.runners.ParentRunner.access $ 000 (ParentRunner.java:50) a org.junit. runners.ParentRunner $ 2.evaluate (ParentRunner.java:222) a org.junit.runners.ParentRunner.run (ParentRunner.java:300) a org.junit.runners.Suite.runChild (Suite.java:128) presso org.junit.runners.Suite.runChild (Suite.java:24) a org.junit.runners.ParentRunner $ 3.run (ParentRunner.java:231) a org.junit.runners.ParentRunner $ 1.schedule (ParentRunner.java:60) a org.junit.runners.ParentRunner.runChildren (ParentRunner.java:229) a org.junit.runners.ParentRunner.access $ 000 (ParentRunner .java: 50) a org.junit.runners.ParentRunner $ 2.valore (ParentRunner.java:222) a org.junit.runners.ParentRunner.run (ParentRunner.java:300) a org.junit.runner. JUnitCore.run (JUnitCore.java:157) a org.junit.runner.JUnitCore.run (JUnitCore.java:136) a android.support.test.runner.AndroidJUnitRunner.onStart (AndroidJUnitRunner.java:270) a android.app.Instrumentation $ InstrumentationThread.run (Instrumentation.java:1551)
Ho letto i documenti Espresso e Dagger e ho cercato senza problemi attraverso i problemi su Github. Apprezzerei qualsiasi aiuto che chiunque possa fornire. Grazie in anticipo.
Modifica # 1
ho seguito il suggerimento di Daniel di estendere il test runner e checkout la VerifyError, e ha ottenuto la seguente analisi dello stack:
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
Questo mi indicò Mockito. Mi mancavano le librerie mockito e dexmaker necessarie.
ho aggiornato il mio dipendenze a:
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'
}
ho MyCustomModule anche overrode, che aveva bisogno di includere EspressoRemoteResourcesModule. Una volta che ho fatto queste cose ha iniziato a funzionare.
Provato questo, ora ho: Test su nexus_5_android_4_0_3 (AVD) - 4.1.1 non riuscito: esecuzione strumentazione non riuscita a causa di 'java.lang.VerifyError' : app: connectedAndroidTest FAILED com.android.builder.testing.ConnectedDevice> hasTests [nexus_5_android_4_0_3 (AVD) - 4.1 .1] [31mFAILED [0m Nessun test trovato. Questo sembra essere un nuovo terreno. C'è un altro metodo che ho bisogno di sovrascrivere per farlo rilevare i test? – jameskbride
Puoi incollare l'intero 'VerifyError' (dovrebbe essere in logcat, credo) e qualsiasi avviso' dalvikvm'? 'Nessun test trovato di solito significa che c'è stato un errore durante l'installazione del corridore, prima dell'inizio dei test. –
Vedere la mia modifica sopra. La versione TL; DR mi ha indirizzato nella giusta direzione estendendo il runner di test e esaminando VerifyError, che mi ha indirizzato verso Mockito e Dexmaker. Grazie per l'aiuto! – jameskbride