首先,我正在尝试想出一些在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;
}
}
}