0

J'ai commencé à utiliser les tests d'interface utilisateur Espresso. Je prépare MockTestRunner personnalisé, MockApplication pour les composants d'initialisation Dagger et j'ai défini des modules fictifs aussi. Il ressemble à ça:Le test a échoué: l'exécution de l'instrument a échoué en raison de 'android.os.NetworkOnMainThreadException'

public class MockTestRunner extends AndroidJUnitRunner { 
    public Application newApplication(ClassLoader cl, String className, Context context) 
      throws InstantiationException, IllegalAccessException, ClassNotFoundException { 
     return super.newApplication(cl, MockMyApplication.class.getName(), context); 
    } } 

MyApp est prolongé par

public class MockQrApplication extends MyApp { 
    private MockWebServer mockWebServer; 

    protected void initComponent() { 
     mockWebServer = new MockWebServer(); 

     component = DaggerMyAppComponent 
       .builder() 
       .myAppModule(new MyAppModule(this)) 
       .busModule(new BusModule()) 
       .apiModule(new MockApiModule(mockWebServer)) 
       .facebookModule(new FacebookModule()) 
       .dataManagerModule(new DataManagerModule()) 
       .greenDaoModule(new GreenDaoModule()) 
       .trackModule(new TrackModule(this)) 
       .build(); 

     component.inject(this); 
    } 
} 

J'ai ajouté testInstrumentationRunner dans gradle

defaultConfig { 
     .... 
     multiDexEnabled true 

     testInstrumentationRunner "a.b.c.MockTestRunner" 
    } 

Je veux effectuer des tests de connexion dans mon LoginActivity

@RunWith(AndroidJUnit4.class) 
@LargeTest 
public class LoginActivityTest { 
    protected Solo solo; 

    @Rule 
    public ActivityTestRule<LoginActivity> activityTestRule = new ActivityTestRule(LoginActivity.class); 

    @Before 
    public void setUp() throws Exception { 
     initVariables(); 
    } 

    protected void initVariables() { 
     solo = new Solo(InstrumentationRegistry.getInstrumentation(), activityTestRule.getActivity()); 
    } 

    @Test 
    public void testLayout() { 
     solo.waitForFragmentByTag(LoginFragment.TAG, 1000); 

     onView(withId(R.id.email_input)).perform(clearText(), typeText("[email protected]")); 
     onView(withId(R.id.pass_input)).perform(clearText(), typeText("qqqqqqqq")); 
     onView(withId(R.id.login_button)).perform(click()); 

     solo.waitForDialogToOpen(); 
    } 
} 

Quand je veux exécuter mes tests, je suis arrivé:

Client not ready yet.. 
Started running tests 
Test running failed: Instrumentation run failed due to 'android.os.NetworkOnMainThreadException' 
Empty test suite. 

[Modifier]

C'est MockApiModule qui étend la demande ApiModule API de classe

public class MockApiModule extends ApiModule { 
    private MockWebServer mockWebServer; 

    public MockApiModule(MockWebServer mockWebServer) { 
     this.mockWebServer = mockWebServer; 
    } 

    @Override 
    public OkHttpClient provideOkHttpClient(DataManager dataManager) { 
     return new OkHttpClient.Builder() 
       .build(); 
    } 

    @Override 
    public Retrofit provideRetrofit(OkHttpClient okHttpClient) { 
     Retrofit retrofit = new Retrofit.Builder() 
       .baseUrl(mockWebServer.url("/"))  // throw NetworkOnMainThreadException 
       .addConverterFactory(NullOnEmptyConverterFactory.create()) 
       .addConverterFactory(GsonConverterFactory.create(new Gson())) 
       .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
       .client(okHttpClient) 
       .build(); 
     return retrofit; 
    } 

    @Override 
    public ApiService provideApiService(Retrofit retrofit) { 
     return retrofit.create(ApiService.class); 
    } 

    @Override 
    public ApiClient provideApiManager(Application application, ApiService apiService, DataManager dataManager) { 
     return new MockApiClient(application, apiService, dataManager, mockWebServer); 
    } 
} 

de connexion ressemble à ça:

apiService.postLoginUser(userLoginModel).enqueue(new Callback<JsonObject>() { 
      @Override 
      public void onResponse(Call<JsonObject> call, Response<JsonObject> response) { 
       if (response.isSuccess()) { 
        LoginResponse loginResponse = null; 
        try { 
         loginResponse = gson.fromJson(MockResponse.getResourceAsString(this, "login.json"), LoginResponse.class); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
        callback.onLoginSuccess(loginResponse); 
       } else { 
        callback.onLoginFail(response.errorBody().toString()); 
       } 
      } 

      @Override 
      public void onFailure(Call<JsonObject> call, Throwable t) { 
       callback.onLoginFail(t.getMessage()); 
      } 
     }); 

Cela fonctionne si je change MockMyApplication dans MyApp classe d'application dans MockTestRunner

Je reçois stracktrace

android.os.NetworkOnMainThreadException 
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1285) 
at java.net.InetAddress.lookupHostByName(InetAddress.java:431) 
at java.net.InetAddress.getAllByNameImpl(InetAddress.java:252) 
at java.net.InetAddress.getByName(InetAddress.java:305) 
at okhttp3.mockwebserver.MockWebServer.start(MockWebServer.java:303) 
at okhttp3.mockwebserver.MockWebServer.start(MockWebServer.java:293) 
at okhttp3.mockwebserver.MockWebServer.maybeStart(MockWebServer.java:143) 
at okhttp3.mockwebserver.MockWebServer.getHostName(MockWebServer.java:172) 
at okhttp3.mockwebserver.MockWebServer.url(MockWebServer.java:198) 
at com.mooduplabs.qrcontacts.modules.MockApiModule.provideRetrofit(MockApiModule.java:38) 
at com.mooduplabs.qrcontacts.modules.ApiModule_ProvideRetrofitFactory.get(ApiModule_ProvideRetrofitFactory.java:23) 
at com.mooduplabs.qrcontacts.modules.ApiModule_ProvideRetrofitFactory.get(ApiModule_ProvideRetrofitFactory.java:9) 
at dagger.internal.ScopedProvider.get(ScopedProvider.java:46) 
at com.mooduplabs.qrcontacts.modules.ApiModule_ProvideApiServiceFactory.get(ApiModule_ProvideApiServiceFactory.java:23) 
at com.mooduplabs.qrcontacts.modules.ApiModule_ProvideApiServiceFactory.get(ApiModule_ProvideApiServiceFactory.java:9) 
at dagger.internal.ScopedProvider.get(ScopedProvider.java:46) 
at com.mooduplabs.qrcontacts.modules.ApiModule_ProvideApiManagerFactory.get(ApiModule_ProvideApiManagerFactory.java:31) 
at com.mooduplabs.qrcontacts.modules.ApiModule_ProvideApiManagerFactory.get(ApiModule_ProvideApiManagerFactory.java:11) 
at dagger.internal.ScopedProvider.get(ScopedProvider.java:46) 
at com.mooduplabs.qrcontacts.activities.BaseActivity_MembersInjector.injectMembers(BaseActivity_MembersInjector.java:44) 
at com.mooduplabs.qrcontacts.activities.BaseActivity_MembersInjector.injectMembers(BaseActivity_MembersInjector.java:13) 
at com.mooduplabs.qrcontacts.components.DaggerQrContactsAppComponent.inject(DaggerQrContactsAppComponent.java:91) 
at com.mooduplabs.qrcontacts.activities.BaseActivity.init(BaseActivity.java:74) 
at com.mooduplabs.qrcontacts.activities.BaseActivity.onCreate(BaseActivity.java:64) 
at android.app.Activity.performCreate(Activity.java:6367) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110) 
at android.support.test.runner.MonitoringInstrumentation.callActivityOnCreate(MonitoringInstrumentation.java:532) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2404) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2511) 
at android.app.ActivityThread.access$900(ActivityThread.java:165) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1375) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:150) 
at android.app.ActivityThread.main(ActivityThread.java:5621) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684) 
+2

Le message d'erreur est assez clair, vous effectuez un appel réseau dans le thread UI. Comme vous êtes en test instrumenté, il y a un thread UI (principal) et son comportement est le même que lorsque vous lancez l'application sur un périphérique réel. Afficher le code qui pourrait contenir des appels réseau –

+0

Hey, Thx pour votre réponse, j'ai ajouté 'MockApiModule' et demande de connexion. Je comprends le message d'erreur mais je ne sais pas pourquoi. Étant donné que Test ne peut pas démarrer et que le message – Michael

+0

s'affiche, vous ne pouvez pas utiliser votre méthode de connexion à l'API dans le thread de test. Cette fonction est appelée quelque part pendant la méthode setUp()? –

Répondre

0

a couru dans la même question, il faut juste éviter de commencer votre activité tout de suite au cours des essais. Vous pouvez y parvenir en ajustant votre règle de test comme l'extrait ci-dessous,

@Rule 
// Do not launch the activity right away 
public ActivityTestRule<LoginActivity> activityTestRule = new ActivityTestRule(LoginActivity.class, true, false); 

et à partir le serveur web simulé par vous-même lors de l'installation de test. Il se passe essentiellement parce que mockWebServer.url("/") essaie de démarrer le faux serveur pour vous au cas où il n'a pas déjà commencé. Vous devez d'abord le faire si vous ne voulez pas le faire plus tard pendant l'exécution du test (cas NetworkOnMainThreadException).