Reputation: 5496
So i have repository, which provides the Observable to the client. Is there a way i can mock this repository, so i don't need to send location from my emulator or using the real device to gain some Location?
Here is how the interface looks like:
interface RxLocationRepository {
@SuppressLint("MissingPermission")
fun onLocationUpdate(): Observable<Location>
fun stopLocationUpdates()
}
In my client side i use this like this:
class LocationManager(
val rxLocationRepository: RxLocationRepository){
private fun appendGeoEvent(location: Location) {
val locationGeoEvent = LocationGeoEvent(
accuracy = location.accuracy.toDouble(),
latitude = location.latitude,
longitude = location.longitude,
timestampGeoEvent = location.time
)
processGeoEvent(locationGeoEvent)
}
compositeDisposable.add(rxLocationRepository.onLocationUpdate()
.subscribe(Consumer { location ->
appendGeoEvent(location)
}))
....
So i sending this obtained location to my appendGeoEvent method.
I can use for example Mockito, but i don't know how to mock this repository so i can use the fake locations. Also, i want to use Kotlin.
Upvotes: 1
Views: 3167
Reputation: 5496
I needed to setup different Dagger module, which just provide me implementation of this repository - it returns different Observable stream.
I set it up like this.
@Module
abstract class StubLocationRepositoryModule {
@Binds
internal abstract fun bindsRxLocationRepository(stubRxLocationRepository: StubRxLocationRepository) : RxLocationRepository
}
I was just using this in my androidTest package in component.
So my implementation was like this:
just an example:
class StubRxLocationRepository @Inject constructor(val stubLocationParameterName: String) : RxLocationRepository {
val location = Location("test").apply {
latitude = 1.234
longitude = 5.678
accuracy = 20f
time = Date().time
}
override fun onLocationUpdate(): Observable<Location> {
Log.v("StubLocationRepository", "CHOSEN PARAMETER: $stubLocationParameterName")
return when (stubLocationParameterName) {
"highFreq" -> Observable.interval(50, TimeUnit.MILLISECONDS)
.flatMap(
{
Observable.just(location)
}
)
.doOnNext{ t: Location -> Log.v("onLocationUpdate", t.toString()) }
else -> Observable.interval(1, TimeUnit.SECONDS)
.flatMap(
{
Observable.just(location)
}
)
.doOnNext{ t: Location -> Log.v("onLocationUpdate", t.toString()) }
}
}
override fun stopLocationUpdates() {
Log.v("StubLocationRepository", "stopLocationUpdates")
}
}
So in my Dagger Component builder i expose a method which will provide me some parameter in which i will depend in the StubRxLocation implementation - it will return me some stream i need for specific test case.
So the component:
@Singleton
@Component(modules = arrayOf(StubLocationRepositoryModule::class,
LocationTestInstrumentalModule::class, StubRssiRepositoryModule::class))
interface LocationTestInstrumentalComponent{
fun locationClient(): LocationClient
@Component.Builder
interface Builder {
@BindsInstance
fun context(context: Context): Builder
@BindsInstance
fun stubLocationRepositoryParameter(stubLocationRepositoryParameter: String): Builder
fun build(): LocationTestInstrumentalComponent
}
}
So in every test i can bring the mocked repository it like this, which will be ready form me to use for that test case:
@Test
fun someTest(){
val component = DaggerLocationTestInstrumentalComponent.builder().stubLocationRepositoryParameter("highFreq").context(InstrumentationRegistry.getContext()).build()
val client = component.locationClient()
//i can expose some other methods, not only this 'locationClient' in this Component to return me some classes, like this RxLocationRepository(which will behave as i want) and others
}
Upvotes: 0
Reputation: 7058
If using Mockito, you could do something like this:
import android.location.Location
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.junit.MockitoJUnitRunner
import java.util.*
@RunWith(MockitoJUnitRunner::class)
class LocationsTest{
@Test
fun should_return_one_location() {
val location = Location("test").apply {
latitude = 1.234
longitude = 5.678
// ...
}
val mockRepository = mock(RxLocationRepository::class.java)
`when`(mockRepository.onLocationUpdate()).thenReturn(Observable.just(location))
// use the mock
}
}
I am using: testCompile "org.mockito:mockito-core:2.11.0"
Upvotes: 2