目前使用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{ 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.
你永远不会注入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
模块.只有在使用多个复杂模块时才需要这样做.
尝试使用注射构造函数.这就是Dagger所建造的,并且效果最佳.额外的好处是,您现在可以拥有自己的领域private
,就像它们应该的那样.
当使用可注入的构造函数时,实际上只需要providesXXX
在注入接口实例时创建方法,就像我们使用Bar
和BarImpl
.因为,嘿,这正是Dependency Injection的用途,对吧?