Don*_*rty 4 java android unit-testing robolectric dagger-2
我最近将Dagger2应用到Android应用程序中以便于依赖注入,但在这样做后,我的一些测试已停止工作.
现在我想了解如何调整我的测试以使用Dagger2?我正在使用Robolectric来运行我的测试.
以下是我如何使用Dagger2,我最近才学会它,所以这可能是不好的做法,并没有帮助测试,所以请指出我可以做的任何改进.
我有一个AppModule,如下所示:
@Module
public class MyAppModule {
//Application reference
Application mApplication;
//Set the application value
public MyAppModule(Application application) {
mApplication = application;
}
//Provide a singleton for injection
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}
}
Run Code Online (Sandbox Code Playgroud)
我称之为NetworkModule,提供注入对象,如下所示:
@Module
public class NetworkModule {
private Context mContext;
//Constructor that takes in the required context and shared preferences objects
public NetworkModule(Context context){
mContext = context;
}
@Provides
@Singleton
SharedPreferences provideSharedPreferences(){
//...
}
@Provides @Singleton
OkHttpClient provideOKHttpClient(){
//...
}
@Provides @Singleton
Picasso providePicasso(){
//...
}
@Provides @Singleton
Gson provideGson(){
//...
}
}
Run Code Online (Sandbox Code Playgroud)
然后组件是这样的:
Singleton
@Component(modules={MyAppModule.class, NetworkModule.class})
public interface NetworkComponent {
//Activities that the providers can be injected into
void inject(MainActivity activity);
//...
}
Run Code Online (Sandbox Code Playgroud)
对于我的测试,我使用的是Robolectric,我的Application类的Test变量如下:
public class TestMyApplication extends TestApplication {
private static TestMyApplication sInstance;
private NetworkComponent mNetworkComponent;
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
mNetworkComponent = DaggerTestMyApplication_TestNetworkComponent.builder()
.testMyAppModule(new TestMyAppModule(this))
.testNetworkModule(new TestNetworkModule(this)).build();
}
public static MyApplication getInstance() {
return sInstance;
}
@Override public NetworkComponent getNetComponent() {
return mNetworkComponent;
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我正在尝试确保使用我的Dagger2模块的模拟版本,这些也被模拟,模拟的MyAppModule返回TestMyApplication和模拟的NetworkModule返回模拟对象,我还有一个模拟的NetworkComponent,它扩展了真实NetworkComponent.
在测试的设置中,我使用Robolectric创建Activity,如下所示:
//Build activity using Robolectric
ActivityController<MainActivity> controller = Robolectric.buildActivity(MainActivity.class);
activity = controller.get();
controller.create(); //Create out Activity
Run Code Online (Sandbox Code Playgroud)
这会创建Activity并启动onCreate,这就是问题发生的地方,在onCreate中我有以下代码片段将Activity注入组件,因此它可以像这样使用Dagger2:
@Inject Picasso picasso; //Injected at top of Activity
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
MyApplication.getInstance().getNetComponent().inject(this);
picasso.load(url).fetch();
Run Code Online (Sandbox Code Playgroud)
这里的问题是,当运行测试时,我在picasso变量上得到一个NullPointerException,所以我猜我的Dagger2设置在测试的某个地方有一个缺失的链接?
编辑:添加TestNetworkModule
@Module
public class TestNetworkModule {
public TestNetworkModule(Context context){
}
@Provides
@Singleton
SharedPreferences provideSharedPreferences(){
return Mockito.mock(SharedPreferences.class);
}
@Provides @Singleton
Gson provideGson(){
return Mockito.mock(Gson.class);
}
@Provides @Singleton
OkHttpClient provideOKHttpClient(){
return Mockito.mock(OkHttpClient.class);
}
@Provides @Singleton
Picasso providePicasso(){
return Mockito.mock(Picasso.class);
}
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*e C 10
您无需在TestApplication和模块中添加setter.您正在使用Dagger 2,因此您应该使用它来在测试中注入依赖项:
首先在MyApplication中创建一个检索ApplicationComponent的方法.此方法将在TestMyApplication类中重写:
public class MyApplication extends Application {
private ApplicationComponent mApplicationComponent;
public ApplicationComponent getOrCreateApplicationComponent() {
if (mApplicationComponent == null) {
mApplicationComponent = DaggerApplicationComponent.builder()
.myAppModule(new MyAppModule(this))
.networkModule(new NetworkModule())
.build();
}
return mApplicationComponent;
}
}
Run Code Online (Sandbox Code Playgroud)
然后创建一个TestNetworkComponent:
@Singleton
@Component(modules = {MyAppModule.class, TestNetworkModule.class})
public interface TestApplicationComponent extends ApplicationComponent {
void inject(MainActivityTest mainActivityTest);
}
Run Code Online (Sandbox Code Playgroud)
在TestNetworkModule中返回一个mock
@Provides
@Singleton
Picasso providePicasso(){
return Mockito.mock(Picasso.class);
}
Run Code Online (Sandbox Code Playgroud)
在TestMyApplication中,构建TestNetworkComponent:
public class TestMyApplication extends MyApplication {
private TestApplicationComponent testApplicationComponent;
@Override
public TestApplicationComponent getOrCreateApplicationComponent() {
if (testApplicationComponent == null) {
testApplicationComponent = DaggerTestApplicationComponent
.builder()
.myAppModule(new MyAppModule(this))
.testNetworkModule(new TestNetworkModule())
.build();
}
return testApplicationComponent;
}
}
Run Code Online (Sandbox Code Playgroud)
然后在MainActivityTest中运行应用程序标记并注入依赖项:
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21, application = TestMyApplication.class)
public class MainActivityTest {
@Inject
Picasso picasso;
@Before
public void setup() {
((TestMyApplication)RuntimeEnvironment.application).getOrCreateApplicationComponent().inject(this);
Mockito.when(picasso.load(Matchers.anyString())).thenReturn(Mockito.mock(RequestCreator.class));
}
@Test
public void test() {
Robolectric.buildActivity(MainActivity.class).create();
}
}
Run Code Online (Sandbox Code Playgroud)
你的Picasso领域已经注入你的Picasso模拟现在你可以与之互动.
| 归档时间: |
|
| 查看次数: |
4702 次 |
| 最近记录: |