Unit testing 单元测试一个已启动的服务,其中注入了几个字段?
我是个新手 TL;医生:Unit testing 单元测试一个已启动的服务,其中注入了几个字段?,unit-testing,android-service,robolectric,dagger,Unit Testing,Android Service,Robolectric,Dagger,我是个新手 TL;医生: 如果安卓服务使用Dagger将任何字段注入其中,那么为了实际执行注入,我需要该服务的一个实例 在Robolectric测试中,这对应于MyService service=roblectric.buildService(MyService.class).get()。然后,objectGraph.inject(服务) 然而,实际启动MyService的其余代码仍然使用context.startService(context,MyService.class) 问题:Dag
- 如果安卓
使用Dagger将任何字段注入其中,那么为了实际执行注入,我需要该服务
服务的一个实例
- 在Robolectric测试中,这对应于
。然后,MyService service=roblectric.buildService(MyService.class).get()
objectGraph.inject(服务)代码>
- 然而,实际启动
的其余代码仍然使用MyService
context.startService(context,MyService.class)代码>
假设我有一个
服务
,如下所示:
public class MyService {
@Inject Parser parser;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String data = intent.getStringExtra("data_to_be_parsed");
parser.parse(data);
}
}
在代码的其他地方,我有一个ApicClient类,它可以执行以下操作:
public class ApiClient{
public static void parseInBackground(Context context, String data){
//This service does not have its fields injected
context.startService(new Intent(context, MyService.class).putExtra("data_to_be_parsed", data));
}
}
该parseInBackground
方法将从活动中调用,以响应用户交互
现在,我正在关注TDD,因此,我还没有为此编写应用程序模块。以下是测试模块:
@Module(injects = MyService.class)
public class TestModule {
@Provides @Singleton Parser provideParser(){
return new MockParser();
}
}
最后,测试用例:
@RunWith(Robolectric.class)
public class ApiTest {
@Test
public void parseInBackground_ParsesCorrectly(){
//This service has its fields injected
MyService service = Robolectric.buildService(MyService.class).get();
ObjectGraph.create(new TestModule()).inject(service);
ApiClient.parseInBackground(Robolectric.application, "<user><name>droid</name></user>");
//Asserts here
}
}
但是,我在这里硬编码TestModule
Dagger中有没有一个现成的习惯用法可以为这种情况设置依赖关系?在测试或服务中硬编码模块是错误的。更好的方法是通过自定义的
应用程序
对象执行创建,该对象将依次保存singletonObjectGraph
对象。例如:
// in MyService class
@Override public void onCreate() {
super.onCreate();
MyApp.from(context).inject(this);
}
// in MyApp class
public static MyApp from(Context context) {
return (MyApp) context.getApplicationContext();
}
//...
private ObjectGraph objectGraph;
@Override public void onCreate() {
// Perform Injection
objectGraph = ObjectGraph.create(getModules());
objectGraph.inject(this);
}
public void inject(Object object) {
objectGraph.inject(object);
}
protected Object[] getModules() {
// return concrete modules based on build type or any other conditions.
}
或者,您可以将最后一个方法重构成单独的类,并针对不同的风格或构建类型进行不同的实现。另外,您可能希望在
TestModule
的注释中设置overrides=true
。我仍然不明白。在您的示例中,第二个onCreate()
在MyService
中,对吗?如果我需要重写getModules()
,那么我必须在我的应用程序代码和测试代码中创建一个不同的MyService
子类。好的,在src/main
和src/test
中不能有同名的类。因此,服务的**类基本上成为ApiClient
类的依赖项。这里缺少什么吗?没有。只有第一个代码块来自MyService
。其他所有内容都来自您的自定义应用程序MyApp。对于测试,您可以定义MyTestApp
,它将扩展MyApp
并覆盖getModules
方法,只为测试添加匕首模块。啊-我现在明白您的意思了。我试试你的建议。谢谢。我意识到我的问题有很多问题。首先,作为测试的一部分,我试图实际启动一项服务——这不是Robolectric的目的。我把那个部分转移到一个单独的仪器测试中。我现在正在研究如何使用应用程序子类正确地实现依赖项注入部分。一旦我的东西开始工作,我会发布一个答案。@curioustechizen你到底需要什么帮助?我想我的回答中提到了一切,不是吗?
// in MyService class
@Override public void onCreate() {
super.onCreate();
MyApp.from(context).inject(this);
}
// in MyApp class
public static MyApp from(Context context) {
return (MyApp) context.getApplicationContext();
}
//...
private ObjectGraph objectGraph;
@Override public void onCreate() {
// Perform Injection
objectGraph = ObjectGraph.create(getModules());
objectGraph.inject(this);
}
public void inject(Object object) {
objectGraph.inject(object);
}
protected Object[] getModules() {
// return concrete modules based on build type or any other conditions.
}