0

我已經開始使用UI測試Espresso。我準備自定義MockTestRunner,MockApplication初始化Dagger組件,我也定義了模擬模塊。它看起來像:測試運行失敗:由於'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

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); 
    } 
} 

我加testInstrumentationRunner擴展到gradle

defaultConfig { 
     .... 
     multiDexEnabled true 

     testInstrumentationRunner "a.b.c.MockTestRunner" 
    } 

我想運行測試登錄我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(); 
    } 
} 

當我想運行我的測試中,我得到了:

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

[編輯]

這是MockApiModule延伸ApiModule

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); 
    } 
} 

API登錄請求看起來像這樣:

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()); 
      } 
     }); 

它工作,如果我改變MockMyApplicationMyApp級應用的MockTestRunner

我得到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

錯誤消息非常明確,您正在UI線程內進行網絡調用。當你在儀表測試中,有一個UI(主)線程,他的行爲與在真實設備上啓動應用程序時的行爲相同。顯示可能包含網絡調用的代碼 –

+0

嘿,Thx爲您的答案,我添加了'MockApiModule'和登錄請求。我瞭解錯誤消息,但我不知道原因。由於Test無法啓動,我收到 – Michael

+0

的消息,因此無法在測試線程中使用您的API登錄方法。在setUp()方法中調用某個函數嗎? –

回答

0

跑進類似的問題,只是避免啓動你的活動在測試過程中的時候了。您可以通過調整您的測試規則,如下面的代碼片段實現這一目標,

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

,然後測試設置中開始自己的模擬Web服務器。這基本上是因爲mockWebServer.url("/")試圖爲您啓動模擬服務器,以防它尚未啓動。如果您不想在測試執行期間(NetworkOnMainThreadException情況)稍後執行此操作,則需要先執行此操作。

相關問題