目前使用dagger进行测试,我想要做的是实例化并注入不同的Bar实现。如何在提供的字段中注入字段? 例如:
模块:
@Module(
injects = {
Main.class
},
complete = false,
library = true
)
public class ExampleTestModule {
@Provides
public Foo providesFoo() {
return new Foo();
}
@Provides
public Bar providesBar(BarImpl impl) {
// return new BarImpl(); // null
return impl;
}
}
主:
public class Main {
@Inject
Foo foo;
}
富:
public class Foo {
@Inject
Bar bar;
}
栏:
public interface Bar {
}
BarImpl
public class BarImpl implements Bar {
}
测试用例:
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
public void testFoo() {
Main main = new Main();
ObjectGraph.create(new ExampleTestModule()).inject(main);
assertNotNull(main.foo);
}
public void testFooBar() {
Main main = new Main();
ObjectGraph.create(new ExampleTestModule()).inject(main);
assertNotNull(main.foo.bar);
}
}
Main.Foo不为null,但Main.Foo.Bar为null。
答案 0 :(得分:9)
您永远不会将bar
注入foo
。
ObjectGraph.create(new ExampleTestModule()).inject(main);
此行仅查看由main
注释的@Inject
字段,并将其注入。没有递归行为。
让我们一步一步走:
您在complete = false
中提供了library = true
和Module
。你应该只在必要时才使用它们。当出现问题时,Dagger会给你警告,这些属性会压制这些警告。例如,删除它们会在编译时引发以下警告:
Error:(11, 8) error: No injectable members on BarImpl. Do you want to add an injectable constructor? required by providesBar(BarImpl) for ExampleTestModule.
让我们向BarImpl
添加一个空的可注入构造函数,因为它建议:
public class BarImpl implements Bar {
@Inject
BarImpl(){
}
}
编译会出现新错误:
Error:(11, 8) error: Graph validation failed: You have these unused @Provider methods:
1. ExampleTestModule.providesBar()
Set library=true in your module to disable this check.
显然,providesBar()
从未使用过。这意味着,bar
中的Foo
字段永远不会被注入。你可以做两件事:
手动注入bar
:
ObjectGraph graph = ObjectGraph.create(new ExampleTestModule());
graph.inject(main);
graph.inject(main.foo);
使用可注射构造函数(首选项):
public class Foo {
Bar bar;
@Inject
Foo(Bar bar){
this.bar = bar;
}
}
使用injectable构造函数,您现在将在providesFoo()
中出现编译错误,因为您未在Bar
构造函数中提供Foo
实例。关于Dagger的好处是,您可以安全地完全删除此方法。由于Foo
注释了@Injectable
,因此它需要注入一个Foo
实例,它使用此构造函数。当它使用这个构造函数时,它注意到它需要一个Bar
实例,并注入它。
最后,我们可以从@Inject
中的Foo
字段中删除Main
注释,并创建一个可注入的构造函数。使用ObjectGraph.get(Class<?>)
,我们可以检索完全实例化的Main
实例。
最终结果应如下所示:
模块:
@Module(
injects = Main.class
)
public class ExampleTestModule {
@Provides
public Bar providesBar(BarImpl impl) {
return impl;
}
}
主要强>
public class Main {
Foo foo;
@Inject
Main(Foo foo) {
this.foo = foo;
}
}
<强>富强>
public class Foo {
Bar bar;
@Inject
Foo(Bar bar){
this.bar = bar;
}
}
<强>栏:强>
public interface Bar {
}
<强> BarImpl:强>
public class BarImpl implements Bar {
@Inject
BarImpl(){
}
}
<强> ApplicationTest:强>
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
public void testFoo() {
Main main = ObjectGraph.create(new ExampleTestModule()).get(Main.class);
assertNotNull(main.foo);
}
public void testFooBar() {
Main main = ObjectGraph.create(new ExampleTestModule()).get(Main.class);
assertNotNull(main.foo.bar);
}
}
从结果中,我们可以得出一些结论:
library = true
和complete = false
。只有在使用多个复杂模块时才需要这样做。private
字段,就像它们应该的那样。providesXXX
方法,就像我们对Bar
和BarImpl
所做的那样。 因为,嘿,这正是Dependency Injection的用途,对吗?