jraska / livedata-testing Goto Github PK
View Code? Open in Web Editor NEWTestObserver to easily test LiveData and make assertions on them.
License: Apache License 2.0
TestObserver to easily test LiveData and make assertions on them.
License: Apache License 2.0
Hi,
First of all, thanks for open sourcing this library.
In my project, I've viewmodels which extend AndroidViewModel
class, which means they want an
instance of application
as a constructor parameter. I use the application context in viewmodel for two purposes:
applicationComponent
field so that I can use field injection in my viewmodel. Something like this:MyApplication.getInstance(application).applicationComponent.inject(this)
(getApplication() as MyApplication).getString(R.string....
Hope that's clear.
I can't think of anyway to test this viewmodel without using Android instrumention/RoboElectric.
Do you have any ideas in mind?
As I've seen similar logic for awaiting live data in
https://github.com/google/iosched/blob/master/androidTest-shared/src/main/java/com/google/samples/apps/iosched/androidtest/util/LiveDataTestUtil.kt
It would be useful to implement this logic there :)
Does it need documentation in JavaDoc? I think code is better. Need to add just readme section.
Hi,
Recently I experienced a problem - I wanted to check that my items in LiveData history are going in appropriate order. I didn't want to check that they are exactly the same, I only wanted to check the type of messages.
The problem is that I could test this case either by using assertValueHistory(...)
with EXACT values for history(which I didn't want to do), or by retrieving valueHistory()
and asserting these values manually .
The solution which I made is an extension function, which behaves the same as assertValueHistory
but with predicates:
fun <T> TestObserver<T>.assertValueHistory(vararg predicate: (item: T) -> Boolean) {
val valueHistory = this.valueHistory()
predicate.forEachIndexed { index, function ->
assertTrue("assert history item #$index",function(valueHistory[index]))
}
}
It can be used like that
testObserver.assertValueHistory(
{ it is Type1 },
{ it is Type2 },
{ it is Type3 }
)
I think it will be useful to add it to the library.
Thank you
I get an error saying that my test class cannot access the TestObserver.
I have imported your library using testImplementation 'com.jraska.livedata:testing-ktx:0.6.0' and i am writing my unit tests that is in the Test folder, not the androidTest folder
Testing ViewModel which uses Transformations live data.
Tested on both versions 1.1.1 and 1.1.2
ViewModel has:
val counterList: LiveData<List<CounterDto>> =
Transformations.map(counterRepository.findCounters()) {
it
}
Test:
@Test
fun `get counters live data, when result is empty, return empty` () {
// given
val expected = MediatorLiveData<List<CounterDto>>().init(emptyList())
`when`(counterRepository.findCounters()).thenReturn(expected)
// when
viewModel.counterList.test() // **Cause NPE**
// then
verify(counterRepository, times(1)).findCounters()
}
Stack-trace:
java.lang.NullPointerException
at androidx.lifecycle.MediatorLiveData$Source.plug(MediatorLiveData.java:141)
at androidx.lifecycle.MediatorLiveData.onActive(MediatorLiveData.java:118)
at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:437)
at androidx.lifecycle.LiveData.observeForever(LiveData.java:232)
at com.jraska.livedata.TestObserver.test(TestObserver.java:302)
at com.jraska.livedata.TestObserverKt.test(TestObserver.kt:6)
I tried to upgrade to androidx stable version 2.1.0, but gradle complains that there's a strict dependency on 2.0.0.
My feeling is that this is coming from your library, but I'm not 100% sure. Please close the ticket if you don't think that's the case.
Thanks!
I have a live data that representes the screen state of my view. In onError im setting the screen state to be of error which will show a snackbar and imeadiatly after that I am setting the state to be empty so the user sees a default empty screen. _screenState is my LiveData.
fun loadArticle(articleId: Int) {
refreshSubject
.doOnNext { _screenState.value = ScreenState.loading(true) }
.switchMap { getNewsUseCase.getNewsArticleById(articleId) }
.doOnNext { _screenState.value = ScreenState.loading(false) }
.subscribeIccResult({ result -> _screenState.value = ScreenState.success(result)
}, { error ->
_screenState.value = ScreenState.error(getErrorMessage(error))
_screenState.value = ScreenState.empty()
})
}
When testing the onError branch like so ...
@Test
fun testLoadArticle_ErrorState() {
whenever(getNewsUseCase.getNewsArticleById(anyInt()))
.thenReturn(Observable.just(IccResult.Failure(IccError.Unknown(Exception()))))
articleViewModel.loadArticle(1)
articleViewModel.screenState
.test()
.awaitValue()
.assertHasValue()
.assertValueHistory(ScreenState.empty(), ScreenState.error(R.string.error_loading_failed_message))
verify(getNewsUseCase).getNewsArticleById(anyInt())
}
The test throws an error
Expected :2 [com.icccricket.liteapp.ScreenState$Empty@7d322cad, Error(errorMessage=2131886162)]
Actual :1 [com.icccricket.liteapp.ScreenState$Empty@21be3395]
Basically only showing the last value from my live data, any idea why?
Just incase you hadn't noticed.
The step in CI to upload test results (to attach to the build results) is failing to find the test results files, so they are silently failing.
RxJava has it and can be a convenient way how to perform many assertions at the same time.
https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/
Edit: UPDATE 4/27/2021: We listened to the community and will keep JCenter as a read-only repository indefinitely. Our customers and the community can continue to rely on JCenter as a reliable mirror for Java packages.
Using AndroidX and added testImplementation 'com.jraska.livedata:testing:0.5.0'
to gradle. However, I am unable to import the TestObserver or any classes from the library into my Test code.
I am trying to test mutable data that is stored in a LiveData.
But I couldn't find a proper way of asserting data fields as they come.
In order to really assert the value as it comes, I had to use the map
method in a way it probably wasn't designed to. It feels really awkward using it, even though it works.
Example:
@Test
fun testMutableData() {
val testSubject = subject.measurementEventData.test()
.map { measurementEvent ->
// This is the part that feels awkward
measurementEvent.isHandled shouldBe false
measurementEvent
}
val measurement = Measurement(Sensor.TEMPERATURE, 0.55)
subject.measurementEventData.value = Event(measurement)
testSubject.value().isHandled = true
testSubject
.assertValue { measurementEvent ->
measurementEvent.isHandled
}
}
I propose to add to the TestObserver a list of asserters and test them in every onChanged
alongside the childObservers
.
There are some differences in naming and behaviour between the two libraries, which has confused me a few times when using LiveData testing.
There may be more than I mention below, but the ones that I notice each time:
Maybe I am wrong in thinking that they should work the same way, as they are different libraries, just wondered what your thoughts on it were.
Currently the library uses LiveData.observeForever(Observer)
method and does not allow the clients to change the state of LiveData
. This would be possible by using observe(Lifecycle, Observer)
and adding lifecycle management to Observer API.
At the moment I'm not sure if adding this kind of management is worth the cost of increasing library scope, but I'm opening this based on Medium comment to try it and possibly gather more feedback.
Please comment with possible use cases or just thumbs up.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.