[英]How to inject mocks for class (vs interface) for Dagger
首先,我正在嘗試提出一些合理的方法來在Android上進行單元測試。 我主要關心POJO對象。
在我以前的項目中,我只是通過構造函數注入了所有依賴項。 我在單元測試中創建了模擬,並通過構造函數注入了這些模擬。 缺點是龐大的構造函數,需要通過多層代碼傳遞參數。
顯而易見的解決方案是依賴注入框架。 我看了看其中一些適用於Android的軟件,並決定使用Dagger。 我弄清楚了,並更新了我的應用程序以使用它。
現在,我想更新單元測試,並且不確定如何更改objectGraph以使用模擬(相對於真實類)。
我看到了這篇文章: https ://gist.github.com/adelnizamutdinov/7483963但是,它僅顯示為@Provideds注釋注入模擬。 尚不清楚如何為類注入模擬(當您未在模塊中提供方法時)
更新1(至Eugen Martynov)
基於Dagger文檔:
默認情況下,Dagger通過構造如上所述的請求類型的實例來滿足每個依賴關系。 當您請求CoffeeMaker時,它將通過調用新的CoffeeMaker()並設置其可注入字段來獲得一個。
但是@Inject並非在所有地方都有效:
接口無法構建。 不能注釋第三方類。 必須配置可配置對象!
對於@Inject不足或不方便的這些情況,請使用帶有@Provides注釋的方法>來滿足依賴性。 方法的返回類型定義了它滿足的依賴關系。
因此,看起來無需@Provides就可以滿足依賴關系。 但是,僅用於注入類(與接口)。
更新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注釋的類,而無需您采取任何進一步的措施。 但是,如果您想控制類的創建方式,您只需要在其中一個模塊中添加@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;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.