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情况)稍后执行此操作,则需要先执行此操作。

相关问题