如何为Dagger的类(vs接口)注入模拟

时间:2014-08-21 00:48:56

标签: java android unit-testing dependency-injection dagger

首先,我试图想出一些合理的方法在Android上进行单元测试。我主要关注POJO对象。

在我之前的项目中,我只是通过构造函数注入了所有依赖项。我在我的单元测试中创建了模拟,并通过构造函数注入了这些模拟。缺点是巨大的构造函数和通过多层代码传递参数。

明显的解决方案是依赖注入框架。我看了几个在Android上工作并决定使用Dagger的人。我想出来并更新我的应用程序以使用它。

现在,我想更新unittests,我不知道如何更改objectGraph以使用模拟(vs真实类)。

我看到这篇文章:https://gist.github.com/adelnizamutdinov/7483963 但是,它只显示为@Provideds注释注入模拟。并且不清楚如何为类注入模拟(当你没有在模块中提供方法时)

更新1(对Eugen Martynov)

基于Dagger文档:

  

默认情况下,Dagger通过构造一个来满足每个依赖关系   如上所述的请求类型的实例。当你要求一个   CoffeeMaker,它将通过调用新的CoffeeMaker()和设置获得一个   它的可注射领域。

     

但@Inject并不适用于所有地方:

     

无法构建接口。   第三方课不能   注释。必须配置可配置对象!

     

对于@Inject不足或笨拙的情况,请使用@ Provide-annotated方法>来满足依赖关系。方法的返回类型定义了它满足的依赖性。

因此,看起来它可以在没有@Provides的情况下满足依赖性。但是,只能注入类(vs接口)。

更新2

我的情况如下:

public class Bar {

    @Inject
    Bar() {
    }

    public void doSomethingElse() {
    }
}

public class Foo {

    @Inject
    Bar bar;

    public void doSomething() {
        bar.doSomethingElse();
    }
}

public class FooTest
{

    @Test
    void test_doSomething()
    {
         // I want to create a mock of Bar here and inject it to foo
         // so I can replace all dependencies with mocks before calling 
         // class under test

         foo.doSomething();

    }

}

1 个答案:

答案 0 :(得分:2)

Dagger将负责注入使用@Inject注释的类,而无需您进行任何进一步的操作。但是如果你想控制你的类是如何创建的,你只需要在你的一个模块中添加一个@Provide方法,最好在你的情况下添加一个Test模块然后自己创建。

您的课程默认情况下由Dagger注入 没有任何干预你只需返回值“DEFAULT”

public class MyClass {

    @Inject
    MyClass() {

    }

    public String getValue() {
        return "DEFAULT";
    }
}

某个测试模块中的某处

@Provide
MyClass provideMyClass() {
    return Mockito.mock(MyClass.class)
}

然后运行测试时

@Inject
MyClass myClass;

// code here to actually do the injection

Mockito.when(myClass.getValue()).thenReturn("MOCK");

myClass.getValue(); // Should return "MOCK" instead of "DEFAULT"
编辑:在与@Victor讨论之后,这是我建议他可以实现的目标,但他已经构建了一个小型的现场注入工具来直接实现这一目标。这是代码,以防它对其他任何人都有用。

public class FooTest {

    @Mock
    private Bar mockBar;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void useDaggerModuleWithMock() {
        ObjectGraph objectGraph = ObjectGraph.create(new FooMockedTestModule());

        when(mockBar.doSomethingElse()).thenReturn("MOCK");

        Foo foo = new Foo();
        objectGraph.inject(foo);

        assertThat(foo.doSomething(), is("MOCK"));
    }

    @Module(injects = Foo.class)
    public class FooMockedTestModule {
        // We now take advantage of the module and provide our own implementation of the Bar class instead of letting
        // Dagger do the instance creation itself.
        @Provides
        Bar provideMockBar() {
            return mockBar;
        }
    }
}