junit 测试Android编写状态值

f3temu5u  于 2022-11-11  发布在  Android
关注(0)|答案(1)|浏览(121)

我已经实现了Android视图模型,它公开了Composex 1 m0n1x示例。

class MyViewModel<S> {
    private val _viewState: MutableState<S> = mutableStateOf(initialState)
    val viewState: State<S> = _viewState
    ...
    protected fun setState(newState: S) {
        _viewState.value = newState
    }
}

我想在单元测试中测试它将被设置的值/状态。这只是我想实现的一个简短的例子:

class MyViewModelTest {
    @Test
    fun `when view model initialized then should emit initial state first`() {
        val viewModel = MyViewModel()
        assertEquals(InitialState(), viewModel.viewState.value)
    }

    @Test
    fun `when view model interacted then should emit result state`() {
        val viewModel = MyViewModel()
        val expectedState = NewState()

        viewModel.setState(expectedState)

        assertEquals(expectedState, viewModel.viewState.value)
    }
}

可以测试State<T>吗?如果将状态值存储在视图模型端,如何进行单元测试?

js5cn81o

js5cn81o1#

对于我的特定用例,我使用协程和单向数据流,但通过mutableStateOf公开状态。我希望单元测试初始状态+事件的效果,就像你的情况一样。

视图模型:
class MyViewModel(
  // For injecting test dispatcher
  private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) : ViewModel() {

  // State exposed via delegate
  var state by mutableStateOf(State.Show())
    private set

  fun onEvent(event: Event) {
    when (event) {
      is Event.Greet -> greet(event)
      else -> TODO("Other Stuff")
    }
  }

  private fun greet(greet: Event.Greet) {
    viewModelScope.launch(dispatcher) {
      // Do some, ya know, API stuff!
      state = State.Show("Hello ${greet.name}")
    }
  }
}

state是通过委托公开的,带有一个私有的setter。初始值是Show("Hello")。我们也可以直接用导入设置更新:

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue

调度剂的注射对于控制进展是必不可少的。

状态和事件,以确保完整性
// Encapsulates possible states
sealed class State {

  // Data class calculates equality from the constructor
  // aiding with assertEquals
  data class Show(
    val greeting: String = "Hello"
  ) : State()
}

// ... and possible Events
sealed class Event {
  data class Greet(val name: String) : Event()
}

通过此设置,我们可以进行单元测试:

@ExperimentalCoroutinesApi
@RunWith(MockitoJUnitRunner::class)
class MyViewModelTest {

  val dispatcher = StandardTestDispatcher()

  @Test
  fun `viewModel shows initial state`() = runTest {
    val vm = MyViewModel(dispatcher)
    val expectedState = State.Show()

    // Get the initial state
    val state = vm.state

    assertEquals(expectedState, state)
  }

  @Test
  fun `viewModel shows updated state`() = runTest {
    val vm = MyViewModel(dispatcher)
    val expectedState = State.Show("Hello Robertus")

    // Trigger an event
    vm.onEvent(Event.Greet("Robertus"))

    // Await the change
    dispatcher.scheduler.advanceUntilIdle()

    // Get the state
    val state = vm.state

    assertEquals(expectedState, state)
  }
}

val dispatcher = StandardTestDispatcher()允许我们传递一个调度器,我们可以控制它来等待协程。我们在测试中将它传递给ViewModel,当需要等待它们运行和更新状态时。
注:测试在表达式= runTest { }内。
对于第一个测试viewModel shows initial state,我们获取初始化mutableStatOf时使用的初始值。
在第二个测试viewModel shows updated state中,我们通过在传递Event和获得state之间调用dispatcher.scheduler.advanceUntilIdle()来等待协程完成(调度程序空闲)。
如果没有它,我们将得到初始状态。

相关问题