首先,我试图想出一些合理的方法在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();
}
}
答案 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;
}
}
}