对于 dagger2 模块
@Module
public class MyModule {
@Provides @Singleton public RestService provideRestService() {
return new RestService();
}
@Provides @Singleton public MyPrinter provideMyPrinter() {
return new MyPrinter();
}
}
我们可以将测试模块作为测试
public class TestModule extends MyModule {
@Override public MyPrinter provideMyPrinter() {
return Mockito.mock(MyPrinter.class);
}
@Override public RestService provideRestService() {
return Mockito.mock(RestService.class);
}
}
但是,如果对于一个没有在 dagger 模块中声明的类......
public class MainService {
@Inject MyPrinter myPrinter;
@Inject public MainService(RestService restService) {
this.restService = restService;
}
}
如何创建上述 MainService 的模拟。
请注意,我不打算根据 https://medium.com/@fabioCollini/android-testing-using-dagger-2-mockito-and-a-custom-junit-rule-c8487ed01b56#.9aky15kke 中的份额对 MainService 执行测试,而是我的 MainService 用于我想测试的另一个普通类。例如
public class MyClassDoingSomething() {
@Inject MainService mainService;
public MyClassDoingSomething() {
//...
}
// ...
public void myPublicFunction() {
// This function uses mainService
}
}
最佳答案
这绝对不是在回答你的问题,但在我看来它是相关的,它很有帮助并且太大而无法发表评论。
我经常遇到这个问题,最后总是做“构造函数依赖注入(inject)”。这意味着我不再通过使用 @Inject
注释字段来进行字段注入(inject),而是像这样在构造函数中传递依赖项:
public class MyClassDoingSomething implements DoSomethig {
private final Service mainService;
@Inject
public MyClassDoingSomething(Service mainService) {
this.mainService = mainService;
}
}
请注意构造函数现在如何接收参数并为其设置字段,并且还使用 @Inject
进行注释?我还喜欢让这些类实现一个接口(interface)(也用于 MyService
)——我发现它使 dagger 模块更容易编写,还有其他一些好处:
@Module
public class DoSomethingModule {
@Provides @Singleton public RestService provideRestService() {
return new RestService();
}
@Provides @Singleton public MyPrinter provideMyPrinter() {
return new MyPrinter();
}
@Provides @Singleton public Service provideMyPrinter(MyService service) {
return service;
}
@Provides @Singleton public DoSomethig provideMyPrinter(MyClassDoingSomething something) {
return something;
}
}
(假设 MyService
实现或扩展了 Service
)
到目前为止,您似乎已经知道 dagger 能够自行找出依赖关系图并为您构建所有对象。那么如何对 MyClassDoingSomething
类进行单元测试呢?我什至不在这里使用 Dagger 。我只是手动提供依赖项:
public class MyClassDoingSomethingTest {
@Mock
Service service;
private MyClassDoingSomething something;
@Before
public void setUp() throws Exception {
MockitoAnnotations.init(this);
something = new MyClassDoingSomething(service);
}
// ...
}
如您所见,依赖项是通过构造函数手动传递的。
显然,如果您编写的代码没有可由您调用的构造函数,那么这将不起作用。经典示例是 android Activity 、 fragment 或 View 。有很多方法可以做到这一点,但我个人仍然认为你可以不用 Dagger 以某种方式克服它。如果您正在对具有字段 @Inject MyPresenter myPresenter
的 View 进行单元测试,通常此字段将具有在测试中运行良好的包访问权限:
public class MyViewTest {
@Mock MyPresenter presenter;
private MyView view;
@Before
public void setUp() throws Exception {
MockitoAnnotations.init(this);
view.myPresenter = presenter;
}
}
请注意,这仅在 MyViewTest
和 MyView
位于同一包中时才有效(在 android 项目中通常是这种情况)。
归根结底,如果您仍想使用 Dagger 进行测试,您始终可以创建“测试”模块和组件,它们可以通过在组件中声明方法来注入(inject),例如:
@Inject
public interface MyTestComponent {
void inject(MyClassDoingSomething something);
}
我觉得这种方法还可以,但在我的开发过程中,我更喜欢第一种方法。这也报告了 Robolectric
的问题,即需要 build.gradle
文件中的一些设置才能实际运行 dagger-compiler 进行测试,以便实际生成类。
关于java - 如何模拟未在模块中声明的注入(inject)对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39450182/