How to test with Dagger2 Dependency Injection & Robolectric in Android?

I recently implemented Dagger2 in an Android application for a simple dependency injection, but after that some of my tests stopped working.

Now I'm trying to figure out how to set up my tests to work with Dagger2? I use Robolectric to run my tests.

This is how I use Dagger2, I only recently found out about it, so it may be bad practice and not help in the tests, so please indicate any improvements that I can make.

I have an AppModule that looks like this:

@Module
public class MyAppModule {

    //Application reference
    Application mApplication;

    //Set the application value
    public MyAppModule(Application application) {
        mApplication = application;
    }

    //Provide a singleton for injection
    @Provides
    @Singleton
    Application providesApplication() {
        return mApplication;
    }
}

And what I call NetworkModule, which provides objects for injection, looks like this:

@Module
public class NetworkModule {

private Context mContext;

//Constructor that takes in the required context and shared preferences objects
public NetworkModule(Context context){
    mContext = context;
}

@Provides
@Singleton
SharedPreferences provideSharedPreferences(){
    //...
}

@Provides @Singleton
OkHttpClient provideOKHttpClient(){
    //...
}

@Provides @Singleton
Picasso providePicasso(){
    //...
}

@Provides @Singleton
Gson provideGson(){
    //...
}
}

And then the Component looks like this:

Singleton
@Component(modules={MyAppModule.class, NetworkModule.class})
public interface NetworkComponent {

    //Activities that the providers can be injected into
    void inject(MainActivity activity);
    //...
}

Robolectric, :

public class TestMyApplication extends TestApplication {

    private static TestMyApplication sInstance;
    private NetworkComponent mNetworkComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
        mNetworkComponent = DaggerTestMyApplication_TestNetworkComponent.builder()
                .testMyAppModule(new TestMyAppModule(this))
                .testNetworkModule(new TestNetworkModule(this)).build();
    }

    public static MyApplication getInstance() {
        return sInstance;
    }

    @Override public NetworkComponent getNetComponent() {
        return mNetworkComponent;
    }
}

, , Dagger2, , Moyed MyAppModule TestMyApplication, NetworkModule , NetworkComponent, NetworkComponent.

Robolectric :

//Build activity using Robolectric
ActivityController<MainActivity> controller = Robolectric.buildActivity(MainActivity.class);
activity = controller.get();

controller.create(); //Create out Activity

Activity onCreate, . onCreate Activity , Dagger2 :

@Inject Picasso picasso; //Injected at top of Activity

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
MyApplication.getInstance().getNetComponent().inject(this); 

picasso.load(url).fetch();

, NullPointerException picasso, , , Dagger2 - ?

EDIT: TestNetworkModule

@Module
public class TestNetworkModule {

    public TestNetworkModule(Context context){

    }

    @Provides
    @Singleton
    SharedPreferences provideSharedPreferences(){
        return Mockito.mock(SharedPreferences.class);
    }


    @Provides @Singleton
    Gson provideGson(){
        return Mockito.mock(Gson.class);
    }

    @Provides @Singleton
    OkHttpClient provideOKHttpClient(){
        return Mockito.mock(OkHttpClient.class);
    }

    @Provides @Singleton
    Picasso providePicasso(){
        return  Mockito.mock(Picasso.class);
    }

}
+4
2

TestApplication . Dagger 2, :

MyApplication ApplicationComponent. TestMyApplication:

public class MyApplication extends Application {

    private ApplicationComponent mApplicationComponent;

    public ApplicationComponent getOrCreateApplicationComponent() {
        if (mApplicationComponent == null) {
            mApplicationComponent = DaggerApplicationComponent.builder()
                    .myAppModule(new MyAppModule(this))
                    .networkModule(new NetworkModule())
                    .build();
        }
        return mApplicationComponent;
    }
}

TestNetworkComponent:

@Singleton
@Component(modules = {MyAppModule.class, TestNetworkModule.class})
public interface TestApplicationComponent extends ApplicationComponent {
    void inject(MainActivityTest mainActivityTest);
}

TestNetworkModule

@Provides
@Singleton
Picasso providePicasso(){
    return Mockito.mock(Picasso.class);
}

TestMyApplication TestNetworkComponent:

public class TestMyApplication extends MyApplication {

    private TestApplicationComponent testApplicationComponent;

    @Override
    public TestApplicationComponent getOrCreateApplicationComponent() {
        if (testApplicationComponent == null) {
            testApplicationComponent = DaggerTestApplicationComponent
                    .builder()
                    .myAppModule(new MyAppModule(this))
                    .testNetworkModule(new TestNetworkModule())
                    .build();
        }
        return testApplicationComponent;
    }
}

MainActivityTest :

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21, application = TestMyApplication.class)
public class MainActivityTest {

    @Inject
    Picasso picasso;

    @Before
    public void setup() {
        ((TestMyApplication)RuntimeEnvironment.application).getOrCreateApplicationComponent().inject(this);
        Mockito.when(picasso.load(Matchers.anyString())).thenReturn(Mockito.mock(RequestCreator.class));
    }


    @Test
    public void test() {
        Robolectric.buildActivity(MainActivity.class).create();
    }

}

"" "", .

+7

. , .

, . Tube, .

TestMyApplication, :

public class TestMyApplication extends TestApplication {

    private static TestMyApplication sInstance;
    private NetworkComponent mNetworkComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
    }

    public void setModules(MyAppModule applicationModule, NetworkModule networkModule) {
        this.applicationModule = applicationModule;
        this.mNetworkComponent = DaggerApplicationComponent.builder()
                .applicationModule(applicationModule)
                .domainModule(networkModule)
                .build();
    }

    public static MyApplication getInstance() {
        return sInstance;
    }

    @Override public NetworkComponent getNetComponent() {
        return mNetworkComponent;
    }
}

.


. - :

@Module
public class TestNetworkModule {

    private Picasso picassoMock;

    ...

    @Provides @Singleton
    Picasso providePicasso(){
        return picassoMock;
    }

    public void setPicasso(Picasso picasso){
        this.picasso = picasso;
    }
}

.


:

@RunWith(RobolectricGradleTestRunner.class)
public class PicassoTest {

    @Mock Picasso picasso;
    @Mock RequestCreator requestCreator;

    @Before
    public void before(){
        initMocks(this);

        when(picassoMock.load(anyString())).thenReturn(requestCreator);

        TestApplication app = (TestApplication) RuntimeEnvironment.application;

        TestNetworkModule networkModule = new TestNetworkModule(app);
        networkModule.setPicasso(picasso);

        app.setModules(new TestMyAppModule(this), networkModule);
        //Build activity using Robolectric
        ActivityController<MainActivity> controller = Robolectric.buildActivity(MainActivity.class);
        activity = controller.get();
        activity.create();
    }

    @Test
    public void test(){
        //the test
    }

    @Test
    public void test2(){
        //another test
    }
}

, . , .

+1

All Articles