【问题标题】:Mocked multiple times, but mocked value does not change after secondly mocked in different test method多次模拟,但在不同的测试方法中第二次模拟后,模拟值不会改变
【发布时间】:2021-04-10 23:11:33
【问题描述】:

我正在为我的 ViewModel 编写单元测试。我已经模拟了我的数据源,并想测试该数据源返回成功和错误情况。如果我单独运行测试一切正常。

在第一个方法中我模拟返回成功,在第二个方法中我模拟返回错误。当我一起运行这两个测试时(通过单击类名中的运行测试),在第二种方法中,我希望 dataSource.getPackageCard() 返回 ResponseState.Error("error1337") 但是它返回 ResponseState.Success(responseDto)。换句话说,它会记住第一种方法的模拟值。为什么 ?如何解决这个问题?

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

【问题讨论】:

    标签: android unit-testing kotlin testing mocking


    【解决方案1】:

    我终于找到了答案。由于我使用静态存储库 MyRepositoryImpl.getInstance(dataSource),数据源被模拟一次。第二个模拟无效。我做了手动单例,如果它不为null,则在companioan对象中创建,如果nonnull返回对象。这就是我的问题的原因。

    我通过删除上面实现的单例模式解决了这个问题。我使用构造函数注入并以这种方式使我的存储库成为单例。在我的单元测试中,我的存储库不再是单例的。

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

    当我编写以下内容时,我的视图模型测试已修复:

    @Before
        fun setup() {
            MockKAnnotations.init(this)
    
            myRepository = MyRepositoryImpl(dataSource)
            viewModel = MyViewModel(myRepository)
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-12
      • 1970-01-01
      相关资源
      最近更新 更多