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)
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 –
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
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()? –