1

I have a MediatorLiveData living in my viewmodel that is supposed to react to LiveData emissions from the model layer, taking actions and updating its listeners when necessary. For some reason, the sources don't update during testing.

class MyViewModel(private val repository: Repository) : ViewModel() {
    private val liveData1: LiveData<String> = repository.getString1()
    private val livedata2: LiveData<String> = repository.getString2()

    val currentState = MediatorLiveData<MyState>

    init {
        currentState.addSource(liveData1) {
            it?.let { string1 ->
                doSomething()
                currentState.postValue(String1Updated)
            }
        }
        currentState.addSource(liveData2) {
            it?.let { string1 ->
                doSomethingElse()
                currentState.postValue(String2Updated)
            }
        }
    }
}

Mocking an observer and the repository methods doesn't seem to help. doSomething() is never called, and currentState is not updated to String1Updated.

@RunWith(MockitoJUnitRunner::class)
class MyViewModelTest {
    @get:Rule instantTaskExecutorRule = InstantTaskExecutorRule()

    @Mock lateinit var mockRepository: Repository

    @Mock lateinit var mockLiveData1: MutableLiveData<String>

    @Mock lateinit var mockLiveData2: MutableLiveData<String>

    @Mock lateinit var mockStateObserver: Observer<MyState>

    lateinit var myViewModel: MyViewModel

    @Before
    fun setup() {
        whenever(mockRepository.getLiveData1()).thenReturn(mockLiveData1)
        whenever(mockRepository.getLiveData2()).thenReturn(mockLiveData2)

        myViewModel = myViewModel(mockRepository)
    }

    @Test
    fun `Does something when live data 1 is updated`() {
        myViewModel.state.observeForever(mockStateObserver)
        mockLiveData1.postValue("hello world")

        verify(mockStateObserver).onChanged(String1Updated)
    }
}

Even placing observers directly on mockLiveData1 and mockLiveData2 in addition to the observer on the mediator does not cause the sources to be updated in the mediator.

FutureShocked
  • 779
  • 1
  • 10
  • 26

3 Answers3

3

MediatorLiveData needs to have an active Observer for it to trigger its on "onChange" method.

Look at this answer.

spaaarky21
  • 6,524
  • 7
  • 52
  • 65
Archie G. Quiñones
  • 11,638
  • 18
  • 65
  • 107
2

As demonstrated in my post, I was using mock LiveData as sources to the mediator data. These should just be LiveData implementations.

@Before
fun setup() {
    liveData1 = MutableLiveData()
    whenever(mockRepository.getLiveData1()).thenReturn(liveData1)
    liveData1.postValue("initial value")
    myViewModel.state.observeForever(mockStateObserver)
}
FutureShocked
  • 779
  • 1
  • 10
  • 26
1

mockLiveData1 and mockLiveData2 should probably not be mocks.

Then it would work.

(You can also try @Spy, I always forget what that does though. But I think you should just instantiate them as regular MutableLiveData instead of @Mock.)

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428