我最近全神贯注于 Dagger,因为 DI 的概念完全有意义。DI 的一个更好的“副产品”(正如 Jake Wharton 在他的一个演讲中所说)是更容易测试。
所以现在我基本上使用 Espresso 进行一些功能测试,我希望能够将虚拟/模拟数据注入应用程序并让活动显示出来。我猜,这是 DI 的最大优势之一,这应该是一个相对简单的问题。但出于某种原因,我似乎无法绕过它。任何帮助将非常感激。到目前为止,这是我所拥有的(我写了一个反映我当前设置的示例):
public class MyActivity
extends MyBaseActivity {
@Inject Navigator _navigator;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication.get(this).inject(this);
// ...
setupViews();
}
private void setupViews() {
myTextView.setText(getMyLabel());
}
public String getMyLabel() {
return _navigator.getSpecialText(); // "Special Text"
}
}
这些是我的匕首模块:
// Navigation Module
@Module(library = true)
public class NavigationModule {
private Navigator _nav;
@Provides
@Singleton
Navigator provideANavigator() {
if (_nav == null) {
_nav = new Navigator();
}
return _nav;
}
}
// App level module
@Module(
includes = { SessionModule.class, NavigationModule.class },
injects = { MyApplication.class,
MyActivity.class,
// ...
})
public class App {
private final Context _appContext;
AppModule(Context appContext) {
_appContext = appContext;
}
// ...
}
在我的浓缩咖啡测试中,我试图插入一个模拟模块,如下所示:
public class MyActivityTest
extends ActivityInstrumentationTestCase2<MyActivity> {
public MyActivityTest() {
super(MyActivity.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
ObjectGraph og = ((MyApplication) getActivity().getApplication()).getObjectGraph().plus(new TestNavigationModule());
og.inject(getActivity());
}
public void test_SeeSpecialText() {
onView(withId(R.id.my_text_view)).check(matches(withText(
"Special Dummy Text")));
}
@Module(includes = NavigationModule.class,
injects = { MyActivityTest.class, MyActivity.class },
overrides = true,
library = true)
static class TestNavigationModule {
@Provides
@Singleton
Navigator provideANavigator() {
return new DummyNavigator(); // that returns "Special Dummy Text"
}
}
}
这根本行不通。我的 Espresso 测试运行,但 TestNavigationModule 被完全忽略... arr ... :(
我究竟做错了什么?有没有更好的方法来用 Espresso 模拟模块?我已经搜索并看到了使用 Robolectric、Mockito 等的示例。但我只想要纯 Espresso 测试,并且需要用我的模拟模块换掉一个模块。我应该怎么做?
编辑:
所以我采用@user3399328 的方法来定义静态测试模块列表,检查空值,然后将其添加到我的应用程序类中。我仍然没有得到我的测试注入版本的课程。不过我有一种感觉,可能是匕首测试模块定义有问题,而不是我的浓缩咖啡生命周期。我做出假设的原因是我添加了调试语句并发现静态测试模块在应用程序类中注入时是非空的。您能否指出我可能做错的方向。以下是我定义的代码片段:
我的应用程序:
@Override
public void onCreate() {
// ...
mObjectGraph = ObjectGraph.create(Modules.list(this));
// ...
}
模块:
public class Modules {
public static List<Object> _testModules = null;
public static Object[] list(MyApplication app) {
// return new Object[]{ new AppModule(app) };
List<Object> modules = new ArrayList<Object>();
modules.add(new AppModule(app));
if (_testModules == null) {
Log.d("No test modules");
} else {
Log.d("Test modules found");
}
if (_testModules != null) {
modules.addAll(_testModules);
}
return modules.toArray();
}
}
在我的测试类中修改了测试模块:
@Module(overrides = true, library = true)
public static class TestNavigationModule {
@Provides
@Singleton
Navigator provideANavigator()() {
Navigator navigator = new Navigator();
navigator.setSpecialText("Dummy Text");
return navigator;
}
}