Java 如何使用Dagger模块和Robolectric在Activity onResume()上测试模拟交互?
我正在使用Dagger进行依赖注入,它在我的应用程序中运行良好,但我无法测试它。我遵循此模式创建模块依赖关系图: 现在,在我的MainActivity测试类中,我希望能够在调用Activity onResume()方法时验证与模拟的交互 下面是课堂:Java 如何使用Dagger模块和Robolectric在Activity onResume()上测试模拟交互?,java,android,unit-testing,robolectric,dagger,Java,Android,Unit Testing,Robolectric,Dagger,我正在使用Dagger进行依赖注入,它在我的应用程序中运行良好,但我无法测试它。我遵循此模式创建模块依赖关系图: 现在,在我的MainActivity测试类中,我希望能够在调用Activity onResume()方法时验证与模拟的交互 下面是课堂: @Config(emulateSdk = 18) @RunWith(RobolectricDaggerTestRunner.class) public class MainActivityTest extends TestCase { @
@Config(emulateSdk = 18)
@RunWith(RobolectricDaggerTestRunner.class)
public class MainActivityTest extends TestCase {
@Inject MainActivity sut;
public @Mock MyObject mockMyObject;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
ObjectGraph.create(new TestModule()).inject(this);
}
@Test
public void testThatMyActivityDelegatesDoSomethingToMyObject(){
//init
ActivityController<MainActivity> activityController = ActivityController.of(sut);
//run
activityController.create().start().resume();
//verify
Mockito.verify(mockMyObject).doSomething();
}
@Module(
includes = {ActivityModule.class},
injects = MainActivityTest.class,
overrides = true,
library = true
)
class TestModule {
@Provides
MyObject provideMyObject() {
return mockMyObject;
}
}
}
@Config(emulateSdk=18)
@RunWith(RobolectrictDaggerTestRunner.class)
公共类MainActivityTest扩展了TestCase{
@注射主要活性sut;
public@Mock MyObject mockMyObject;
@以前
public void setUp()引发异常{
initMocks(this);
create(newtestmodule()).inject(this);
}
@试验
public void testThatMyActivityDelegatesDoSomethingToMyObject()的测试{
//初始化
ActivityController ActivityController=ActivityController.of(sut);
//跑
activityController.create().start().resume();
//核实
Mockito.verify(mockMyObject.doSomething();
}
@模块(
includes={ActivityModule.class},
injects=MainActivityTest.class,
覆盖=真,
库=真
)
类测试模块{
@提供
MyObject提供MyObject(){
返回mockMyObject;
}
}
}
据我所见,调用了onCreate()
方法,但使用了myObject
的真实实例,而不是模拟的实例。测试失败,出现“需要但未调用-实际上,与此模拟没有任何交互”错误
这可能是因为我尝试使用Robolectric创建的MainActivity与我的TestModule没有关联,因为它是在应用程序级别创建的,但我设法使该测试通过了对MainActivity的显式调用方法,并将myObject.doSomething()放在其中,但我需要的是测试Android生命周期调用
你知道我该如何测试这个吗 之所以使用真实对象,是因为我猜您在
应用程序
类中初始化了ObjectGraph
。当您调用((Application)getApplication()).inject(this)
时,您在测试期间使用的对象图与您刚刚运行应用程序时使用的相同
在本测试中,您将使用MyObject
的模拟实例创建全新的ObjectGraph
。此模拟仅在MainActivityTest
中注入,因为在MainActivity
中调用inject()
时,它使用应用程序中制作的对象图
您可以做的是使TestApplication
类(它必须与应用程序
类具有相同的包,但需要位于测试目录中)扩展您的应用程序,并在其中添加TestModule
以使用mock覆盖真实实例。例如:
MyApplication.java
package com.example.myapp;
公共类MyApplication扩展了应用程序{
对象图;
私人账户;经常账户;
@凌驾
public void onCreate(){
super.onCreate();
graph=ObjectGraph.create(getModules().toArray());
init();
}
void init(){
//测试中不应调用初始化内容
}
列出getModules(){
列表模块=新的ArrayList();
添加(新活动模块(this));
返回模块;
}
公共无效注入(对象){
图形注入(对象);
}
}
TestMyApplication.java
package com.example.myapp;
公共类TestMyApplication扩展了MyApplication{
@凌驾
void init(){
}
@凌驾
列出getModules(){
modules=super.getModules();
modules.add(newtestmodule());
返回模块;
}
}
不久前,我也遇到了同样的问题,但我成功地解决了它,如下所示:
WojciechKo建议在某些情况下可能有效,但我的解决方案可以在测试中不重写应用程序类的情况下工作。区别在于,您仍然需要提供一种在应用程序中注入匕首模块的方法,而不是在应用程序类中实例化它们。这样,您可以在测试类中添加TestModule,以覆盖实际应用程序类中使用的模块
如果您对该链接中提供的解决方案有问题,请告诉我,我们可以进一步调查该问题。您的MainActivity sut
实例来自哪里?是否有其他模块提供此类?何时将MyObject
实例注入sut
?在上面的代码示例中,MainActivity
是使用@inject
注入的,它不是由任何模块提供的,dagger将只使用默认构造函数。我还尝试在我的setup()
方法中创建它,只需执行MainActivity sut=newmainActivity()
它没有任何区别。在MainActivity中,MyObject由Dagger注入:public类MainActivity扩展了BaseActivity{@Inject MyObject MyObject;..
好的,我假设您的MainActivity
构造函数上有@Inject
注释。您具体在哪里将MyObject
注入MainActivity
?只要Dagger使用默认构造函数实例化对象,它就不会注入其字段。 @Inject
不在构造函数中,而是在字段声明中。否,使用Dagger,您不需要专门将对象注入到活动中,Dagger会自动为您执行此操作。您需要做的唯一一件事是创建依赖关系图。我正在我的MainActivity中的onCreated()
方法中执行此操作((Application)getApplication()).inject(this);
。作为提醒,我的代码已完全更新
package com.example.myapp;
public class MyApplication extends Application {
ObjectGraph graph;
private Account currentAccount;
@Override
public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(getModules().toArray());
init();
}
void init() {
// initialization stuff should not be called in tests
}
List<Object> getModules() {
List<Object> modules = new ArrayList<>();
modules.add(new ActivityModule(this));
return modules;
}
public void inject(Object object) {
graph.inject(object);
}
}
package com.example.myapp;
public class TestMyApplication extends MyApplication {
@Override
void init() {
}
@Override
List<Object> getModules() {
modules = super.getModules();
modules.add(new TestModule());
return modules;
}
}