Android Unit Tests with Dagger 2 Android Unit Tests with Dagger 2 android android

Android Unit Tests with Dagger 2


This is currently impossible with Dagger 2 (as of v2.0.0) without some workarounds. You can read about it here.

More about possible workarounds:


You have hit the nail on the head by saying:

application's Component doesn't have inject methods for my test classes

So, to get around this problem we can make a test version of your Application class. Then we can have a test version of your module. And to make it all run in a test, we can use Robolectric.

1) Create the test version of your Application class

public class TestPipeGameApp extends PipeGameApp {    private PipeGameModule pipeGameModule;    @Override protected PipeGameModule getPipeGameModule() {        if (pipeGameModule == null) {            return super.pipeGameModule();        }        return pipeGameModule;    }    public void setPipeGameModule(PipeGameModule pipeGameModule) {        this.pipeGameModule = pipeGameModule;        initComponent();    }}

2) Your original Application class needs to have initComponent() and pipeGameModule() methods

public class PipeGameApp extends Application {    protected void initComponent() {        DaggerPipeGameComponent.builder()            .pipeGameModule(getPipeGameModule())            .build();    }    protected PipeGameModule pipeGameModule() {        return new PipeGameModule(this);    }}

3) Your PipeGameTestModule should extend the production module with a constructor:

public class PipeGameTestModule extends PipeGameModule {    public PipeGameTestModule(Application app) {        super(app);    }}

4) Now, in your junit test's setup() method, set this test module on your test app:

@Beforepublic void setup() {    TestPipeGameApp app = (TestPipeGameApp) RuntimeEnvironment.application;    PipeGameTestModule module = new PipeGameTestModule(app);    app.setPipeGameModule(module);}

Now you can customize your test module how you originally wanted.


In my opinion you can approach this problem by looking at it from a different angle. You will easily be able to unit test your class by not depending upon Dagger for construction class under test with its mocked dependencies injected into it.

What I mean to say is that in the test setup you can:

  • Mock the dependencies of the class under test
  • Construct the class under test manually using the mocked dependencies

We don't need to test whether dependencies are getting injected correctly as Dagger verifies the correctness of the dependency graph during compilation. So any such errors will be reported by failure of compilation. And that is why manual creation of class under test in the setup method should be acceptable.

Code example where dependency is injected using constructor in the class under test:

public class BoardModelTest {  private BoardModel boardModel;  private Random random;  @Before  public void setUp() {    random = mock(Random.class);    boardModel = new BoardModel(random);  }  @Test  ...}public class BoardModel {  private Random random;  @Inject  public BoardModel(Random random) {    this.random = random;  }  ...}

Code example where dependency is injected using field in the class under test (in case BoardModel is constructed by a framework):

public class BoardModelTest {  private BoardModel boardModel;  private Random random;  @Before  public void setUp() {    random = mock(Random.class);    boardModel = new BoardModel();    boardModel.random = random;  }  @Test  ...}public class BoardModel {  @Inject  Random random;  public BoardModel() {}  ...}