Android espresso - 如何使用dagger2注入依赖项

时间:2017-06-12 10:50:23

标签: android dependency-injection android-espresso dagger-2 mockwebserver

使用dagger2将依赖项注入espresso测试是我想要做的。

我想要一种能够使用匕首为我的测试用例提供依赖关系的方法。

特别是我想要用匕首注入MockwebServer类。这是怎么做到的? 我的项目已经设置了匕首。它现在是一个单独的组件,单个组件有5个模块 看起来像这样:

@Singleton
@Component(modules = {AppModule.class, NetworkModule.class, RepositoryModule.class, UseCaseModule.class, ActivityModule.class, PresenterModule.class})
public interface AppComponent {

    void inject(NetworkSessionManager target);
    void inject(SplashActivity target);
    void inject(AuthenticationActivity target);
    void inject(WelcomeActivity target);
    void inject(LoginFragment target);
}

它的工作很精细。但是现在当我移动到androidTest文件夹进行espresso测试时,我将如何使用以下组件:

    //note the NetworkTestModule.class i want to use is defined instead of //networkModule.class
        @Singleton
        @Component(modules = {AppModule.class, NetworkTestModule.class, RepositoryModule.class, UseCaseModule.class, ActivityModule.class, PresenterModule.class})
        public interface AppTestComponent

 {

        void inject(NetworkSessionManager target);
        void inject(SplashActivity target);
        void inject(AuthenticationActivity target);
        void inject(WelcomeActivity target);
        void inject(LoginFragment target);
        void inject (MYTESTCLASS target);
    }

我一直在做的是将AppTestComponent保留在主要源代码中,但它不能以这种方式看到MYTESTCLASS?

我想要注入我的类的原因是,我希望在将它传递给改造之后注入一个mockWebServer类,就像这样的baseurl:

TestNetworkModule.java:

@Provides
@Singleton
public Retrofit provideRetrofit(Converter.Factory converter, OkHttpClient client, @Named(BASE_URL) String baseUrl, MockWebServer server) {
    return new Retrofit.Builder()
            .baseUrl(server.url("/").toString())
            .client(client)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(converter)
            .build();
}

    @Singleton
    @Provides
    MockWebServer providerMockWebServer() {
        return new MockWebServer();
    }
    //....
    }

通过这种方式,我可以获得MockWebServer的参考,并在我的测试中使用它,并对其进行改造,以便我可以进行快速集成测试

同样在gradle我使用以下依赖项请确认:

 compile 'com.google.dagger:dagger:2.9'
testCompile 'com.google.dagger:dagger:2.9'
annotationProcessor 'com.google.dagger:dagger-compiler:2.9'

1 个答案:

答案 0 :(得分:8)

I will try to explain how do it:

In your application class you should have specified Application component which contains your API service:

protected AppComponent initializeAppComponent() {
    return DaggerAppComponent.builder()
            .apiServiceModule(new APIServiceModule(this))
            .otherModules(new otherModules(this))
            .build();
}

And inject like this:

@Override
public void onCreate() {
    applicationComponent = initializeAppComponent();
    applicationComponent.inject(this)}};

It is standard initialization. You need to just move component builder to method which can be overrided later.

In your android Tests package:

Now, you need to create new Application class which extends your application class where you have your dagger component initialization.

So now you can override initializeAppComponent() method and switch your APIServiceModule by the new one which extends previous Module. It should looks like this:

public class MockApp extends App {

@Override
protected AppComponent initializeAppComponent() {
    return DaggerAppComponent.builder()
            .apiServiceModule(new MockAPIServiceModule(this))
            .otherModules(new OtherModules(this))
            .build();
}

@Module
private class MockAPIServiceModule extends APIServiceModule {

    @Override
    public ApiService provideApiService(@Nonnull final Retrofit retrofit,
                                        @Nonnull final Gson gson) {
        return new ApiService() {
            @Override
            public Observable<LoginResponse> login(@Body final LoginRequest loginRequest) {
                return // what you want to
            }
        }
    }
}}

You need to declare which Application class should be used for tests. Now you need to do 2 more things: 1. Create new runner which pointing on new App Class

public class MockTestRunner extends AndroidJUnitRunner{

@Override
public void onCreate(Bundle arguments) {
    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());
    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().build());
    super.onCreate(arguments);
}
@Override
public Application newApplication(ClassLoader cl, String className, Context context)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return super.newApplication(cl, MockApp.class.getName(), context);
}}
  1. Declare which runner will be used in build.gradle.

testInstrumentationRunner ".MockTestRunner"

Thats it. Now your requests will use mocked responses! If you have any question just ask.

Cheers