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



首先,我正在尝试想出一些在Android上进行单元测试的合理方法。我最关心的是POJO对象。

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

显而易见的解决方案是依赖注入框架。我看了几款适用于Android的应用,决定使用Dagger。我弄明白了,并更新了我的应用程序来使用它。

现在,我想更新单元测试,我不确定我如何改变objectGraph使用模拟(vs真实类)。

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

更新1(致Eugen Martynov)

基于Dagger文档:

默认情况下,Dagger通过构造一个如上所述请求类型的实例。当你要求它将通过调用new CoffeeMaker()并设置它的可注入字段。

但是@Inject并不是在所有地方都起作用:

接口不能被构造。第三方类则不能带注释的。必须配置可配置对象!

对于@Inject不够用或不方便的情况,使用@ providers注释的方法>来满足依赖项。方法的返回类型定义了它满足哪个依赖项。

所以,看起来它可以满足没有@ providers的依赖。但是,只能注入类(相对于接口)。

更新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();
    }
}

Dagger将负责注入那些用@Inject注释的类,而不需要你做任何进一步的操作。但是如果你想控制你的类是如何被创建的,你只需要在你的一个模块中添加一个@提供方法,在你的例子中最好是一个测试模块,然后自己创建。

默认情况下由Dagger注入的类在没有任何干预的情况下,只会返回值"DEFAULT"

public class MyClass {
    @Inject
    MyClass() {
    }
    public String getValue() {
        return "DEFAULT";
    }
}

在某个Test模块中

@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;
        }
    }
}

最新更新