使用Dagger 2注入服务时的单元测试改造呼叫

时间:2018-10-14 18:28:24

标签: android unit-testing mockito retrofit2

我使用Dagger 2在Android应用中提供我的所有课程。我想对构造函数中具有Retrofit服务的存储库类进行单元测试。

class MainRepository(private val service: ImageService) {

fun download(username: String, liveData: MutableLiveData<ImageDownloadResult>) {
    service.downloadImage(username).enqueue(object : Callback<ImageResponse> {
        override fun onFailure(call: Call<ImageResponse>, t: Throwable) {
            liveData.value = DownloadFailed(t)
        }

        override fun onResponse(call: Call<ImageResponse>, response: Response<ImageResponse>) {
            if (response.isSuccessful) {
                response.body()?.let {
                    liveData.value = DownloadSuccessful(it.image)
                }
            } else {
                liveData.value = DownloadFailed(
                    when (response.code()) {
                        401 -> Unauthorized()
                        403 -> Forbidden()
                        404 -> NotFound()
                        in 500..599 -> InternalServerError()
                        else -> General()
                    }
                )
            }
        }
    })
}

}

网络模块类以这种方式提供服务:

@Provides
@Singleton
fun provideImageService(gson: Gson, okHttpClient: OkHttpClient): ImageService {
    return Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create(gson))
        .baseUrl(mBaseUrl)
        .client(okHttpClient)
        .build()
        .create(ImageService::class.java)
}

我正在尝试使用Mockito模拟类,但是在download方法中得到了NullPointerException。

public class MainRepositoryTest {

@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@InjectMocks
ImageService service;

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
}

@Test
public void testImageDownload() {
    MutableLiveData<ImageDownloadResult> liveData = new MutableLiveData<>();
    Response<ImageResponse> response = null;
    try {
        response = service.downloadImage("test").execute();
        assertEquals(response.code(), 200);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

请教我如何将服务注入测试,以便在那里可以调用Http调用。谢谢!

1 个答案:

答案 0 :(得分:1)

我认为您在这里有些困惑。在测试中,您似乎在测试服务而不是存储库。需要模拟该服务才能实际返回某些内容,而不是null。

让我们从测试设置开始。您必须声明模拟内容和要测试的内容

public class MainRepositoryTest {

  @Rule
  public MockitoRule mockitoRule = MockitoJUnit.rule();
  @Mock
  ImageService service;
  @InjectMocks
  MainRepository repository;

   //...
 }

您实际上将在此处测试存储库。照原样,您只需获取注入了服务模拟的存储库实例。但是,此模拟将在每次方法调用时返回null。

因此,现在,您需要针对要测试的每种情况进行设置。假设您要测试成功的响应:

@Test
public void testSuccess (){
    when(service.downloadImage("test")).theReturn(<successful response>);

     repository.download("test", <mutable live data>);

     // Now assert something about the live data
}

当使用预期参数调用时,您将必须模拟服务以返回成功的响应。我不确定如何在此处使用实时数据,因为我从未使用过它。我实际上以为改造已经支持了这一点,而您不必手动进行转换。

对于匕首,使用依赖注入非常好。但是,在测试中,通常不会使用匕首注入依赖项。在这里使用嘲笑注释就足够了。