Mocked multiple times, but mocked value does not change after secondly mocked in different test method

I’m writing unit test for my ViewModel. I have mocked my data source and want to test that datasource returns success and error cases. If i run tests individually everything is OK.

In the first method i mocked to return success, in the second method i mocked to return error. When i run these 2 tests together (by clicking run tests in class name), in the second method i want dataSource.getPackageCard() to return ResponseState.Error(“error1337”) however it returns ResponseState.Success(responseDto). In other words, it remembers the mocked value from 1st method. Why ? How to solve that problem ?

@MediumTest
@RunWith(AndroidJUnit4::class)
@ExperimentalCoroutinesApi
class MyViewModelTest {

    @get: Rule
    var instantExecutorRule = InstantTaskExecutorRule()

    @get: Rule
    var mainCoroutineRule = MainCoroutineRule()

    private lateinit var viewModel: MyViewModel

    lateinit var MyRepository: MyRepository

    val responseDto = MyResponseDto().apply {
        val myList = mutableListOf<CardListGroupDTO>()
        myList.add(CardListGroupDTO(cardGroupType = "test",
                headerTitle = "test",
                buttonAll = ButtonDto(title = "test", url = "test")
        ))
        groupList = myList
    }

    @MockK
    lateinit var dataSource: MyDataSource

    @Before
    fun setup() {
        MockKAnnotations.init(this)

        MyRepository = MyRepositoryImpl.getInstance(dataSource)
        viewModel = MyViewModel(MyRepository)
    }

    @After
    fun afterTests() {
        unmockkAll()
        unmockkObject(dataSource)
    }


    @Test
    fun `test successful case`() = runBlockingTest {
        // given
        coEvery {
            dataSource.getPackageCard()
        } returns ResponseState.Success(
                responseDto
        )

        var counter = 0

        viewModel.MyResponseDto.observeForever(
                object : Observer<ResponseState<MyResponseDto>> {
                    override fun onChanged(t: ResponseState<MyResponseDto>) {
                        // println(viewModel.MyResponseDto.value)

                        when (counter) {
                            0 ->
                                Truth.assertThat(t).isEqualTo(ResponseState.Loading(true))
                            1 ->
                                Truth.assertThat(t).isEqualTo(ResponseState.Success(responseDto))
                            2 -> {
                                Truth.assertThat(t).isEqualTo(ResponseState.Loading(false))
                                viewModel.MyResponseDto.removeObserver(this)
                            }
                        }
                        counter++
                    }
                })
        viewModel.getPackageCard()
    }


    @Test
    fun `test error case`() = runBlockingTest {
        val errorMessage = "error1337"

        // given
        coEvery {
            dataSource.getPackageCard()
        } returns ResponseState.Error(
                errorMessage
        )

        var counter = 0

        viewModel.MyResponseDto.observeForever(
                object : Observer<ResponseState<MyResponseDto>> {
                    override fun onChanged(t: ResponseState<MyResponseDto>) {
                        // println(viewModel.MyResponseDto.value)

                        when (counter) {
                            0 ->
                                Truth.assertThat(t).isEqualTo(ResponseState.Loading(true))
                            1 ->
                                Truth.assertThat(t).isEqualTo(ResponseState.Error(errorMessage))
                            2 -> {
                                Truth.assertThat(t).isEqualTo(ResponseState.Loading(false))
                                viewModel.MyResponseDto.removeObserver(this)
                            }
                        }
                        counter++
                    }
                })
        viewModel.getPackageCard()
    }
}

Answer

I found the answer finally. Since i use static repository MyRepositoryImpl.getInstance(dataSource), the datasource is mocked once. Second mock is not valid. I did manual singleton, inside companioan object create if it is not null, if nonnull return the object. This is the cause of my problem.

I solved the problem, by removing the singleton pattern i implemented as the above. I used constructor injection and made my repository singleton in this way. In my unit tests my repository is not singleton any more.

@Singleton
class MyRepositoryImpl @Inject constructor(
     private val myRemoteDataSource: MyRemoteDataSource
) : MyRepository

And my viewmodel test is fixed when i write the following :

@Before
    fun setup() {
        MockKAnnotations.init(this)

        myRepository = MyRepositoryImpl(dataSource)
        viewModel = MyViewModel(myRepository)
    }