Skip to content

Instantly share code, notes, and snippets.

@BenHenning
Created October 29, 2019 06:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BenHenning/8c8bf8b7853526ab55b1b16643b43d94 to your computer and use it in GitHub Desktop.
Save BenHenning/8c8bf8b7853526ab55b1b16643b43d94 to your computer and use it in GitHub Desktop.
interface ImageLoader {
fun load(imageUrl: String, target: CustomTarget<Bitmap>)
}
class GlideImageLoader @Inject constructor(...): ImageLoader {
override fun load(...) {
..
}
}
// Note to Veena: we will inject ImageLoader rather than a Glide-specific one because then we can utilize Dagger to switch out
// the implementation in tests. This is done by having a production-only module bind the Glide version to ImageLoader:
@Module
abstract class GlideModule {
@Binds
abstract fun provideGlideImageLoader(impl: GlideImageLoader): ImageLoader
}
// Note to Veena: this module allows downstream code injecting ImageLoader to get GlideImageLoader by associating the types.
// E.g., the following code when built in production will actually get an instance of GlideImageLoader:
class Factory @Inject constructor(imageLoader: ImageLoader) {
...
}
// Note to Veena: However, we want to use a different ImageLoader instance at test time. This requires two things:
// 1. That we do not include GlideModule in tests (which means that ImageLoader must live in a module that does not
// automatically include modules in tests, like util).
// 2. We must provide the dependency in a test module (it's easy to verify that this is the case: trying to build
// the test without doing any extra work should fail with a Dagger error saying that a provider is missing for
// ImageLoader).
// We can provide a test dependency for ImageLoader like so:
class SomeTest {
@Inject
lateinit var mockImageLoader: ImageLoader // Inject the mock ImageLoader provided below.
// Prepares the ImageLoader for receiving the specified bitmap for the given URL.
private fun prepareImageLoaderForResponse(expectedUrl: String, bitmap: Bitmap) {
// Note to Veena: 'doAnswer', 'anyString', and 'any' are static Mockito imports.
doAnswer { invocation ->
// Note to Veena: this is called each time production code calls load() via the injected ImageLoader.
// The returned value here will be what load() returns, however that's void so we just return null.
// However, the invocation includes arguments like the target that we can use to provide the bitmap.
val customTarget: CustomTarget<Bitmap> = invocation.getArgument(1)
customTarget.onResourceReady(bitmap, /* transition= */ null)
return null
}.when(mockImageLoader).load(anyString(), any())
}
@Module
class TestModule {
@Provides
fun provideImageLoader(): ImageLoader {
// Note to Veena: 'mock' here is a static Mockito import.
return mock(ImageLoader::class.java) // return a Mockito mock of ImageLoader
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment