原文:Mock Application in Espresso for Dependency Injection
作者:Chiu-Ki Chan
譯者:lovexiaov
我看了 Artem Zinnatullin 寫的使用 Dagger,Robolectric 和 InStrumentation 在單元測試,集成測試與功能測試中模擬依賴(譯者注:這里將鏈接替換成了中譯版本,文章中有原文鏈接)這篇好文。其中我最喜歡的部分是在測試中使用不同的 application
來提供不同的依賴,而我決定使用 Espresso 實現(xiàn)它。
通過自定義測試運行器模擬 application
我當(dāng)前實現(xiàn)依賴注入(譯者注:下文統(tǒng)一使用 DI)的方法是在我的測試 application 中暴露一個 setComponent
函數(shù)來提供測試組件,這樣并不是太好,因為理想情況下 application 中不能包含測試指定代碼。
一種新的實現(xiàn)方式是在 androidTest
文件夾中使用 application 的子類 ,并在測試時通過自定義測試運行器加載它。
public class DemoApplication extends Application {
private final DemoComponent component = createComponent();
protected DemoComponent createComponent() {
return DaggerDemoApplication_ApplicationComponent.builder()
.clockModule(new ClockModule())
.build();
}
public DemoComponent component() {
return component;
}
}
在此 application 中,我們使用 createComponent()
實例化的 DemoComponent
,并且將它存儲為 final
變量待以后使用。
public class MockDemoApplication extends DemoApplication {
@Override
protected DemoComponent createComponent() {
return DaggerMainActivityTest_TestComponent.builder()
.mockClockModule(new MockClockModule())
.build();
}
}
測試時,我們繼承自己的 application 并重寫 createComponent
來提供測試組件。
我們需要自定義測試運行器以在測試是使用模擬 application:
public class MockTestRunner extends AndroidJUnitRunner {
@Override
public Application newApplication(
ClassLoader cl, String className, Context context)
throws InstantiationException,
IllegalAccessException,
ClassNotFoundException {
return super.newApplication(
cl, MockDemoApplication.class.getName(), context);
}
}
我們給出 MockDemoApplication.class.getName()
作為類名,這樣測試運行器將會加載模擬 application 而不是真實的 application。
按應(yīng)用還是按測試?
此方式與 setComponent
有些許不同,因為我們只初始化測試組件一次,而不是每個測試方法執(zhí)行前都要初始化。確保你在每次測試方法執(zhí)行前都清除了測試模塊的狀態(tài),這樣每個測試方法都能從零開始執(zhí)行。
源碼
我已經(jīng)在我的兩個倉庫中使用了此方式:
- android-test-demo:迷你樣例演示的此概念。
- friendspell:一個真實的應(yīng)用展示了怎樣在每個測試之前清除狀態(tài)。