Как издеваться над реактивным репозиторием, который возвращает Observable

Поэтому у меня есть репозиторий, который предоставляет наблюдаемому клиенту. Есть ли способ, которым я могу издеваться над этим репозиторием, поэтому мне не нужно отправлять местоположение из моего эмулятора или использовать реальное устройство, чтобы получить какое-то местоположение?

Вот как выглядит интерфейс:

interface RxLocationRepository { @SuppressLint("MissingPermission") fun onLocationUpdate(): Observable<Location> fun stopLocationUpdates() } 

В моей стороне клиента я использую это следующим образом:

 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) })) .... 

Поэтому я отправляю это полученное местоположение в мой метод appendGeoEvent.

Я могу использовать, например, Mockito, но я не знаю, как издеваться над этим репозиторием, поэтому я могу использовать поддельные локации. Кроме того, я хочу использовать Kotlin.

Если вы используете Mockito, вы можете сделать что-то вроде этого:

 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 } } 

Я использую: testCompile "org.mockito:mockito-core:2.11.0"

Мне нужно было установить другой модуль Dagger, который просто предоставил мне реализацию этого репозитория – он возвращает другой поток Observable.

Я настроил это так.

 @Module abstract class StubLocationRepositoryModule { @Binds internal abstract fun bindsRxLocationRepository(stubRxLocationRepository: StubRxLocationRepository) : RxLocationRepository } 

Я просто использовал это в своем пакете androidTest в компоненте.

Итак, моя реализация была такой:

просто пример:

 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") } } 

Поэтому в моем компоновщике компонентов Dagger я выставляю метод, который предоставит мне некоторый параметр, в котором я буду зависеть в реализации StubRxLocation – он вернет мне некоторый поток, который мне нужен для конкретного тестового примера.

Таким образом, компонент:

 @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 } } 

Поэтому в каждом тесте я могу принести издеваемое хранилище, как это, что будет готово для меня использовать для этого тестового примера:

 @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 }