在开发智能家居相关的无线组网应用时,界面和逻辑的稳定性直接影响用户体验。比如你家里的Wi-Fi中继器管理App,点一下刷新却卡住,或者设备状态更新不及时,很可能就是背后代码没测到位。用MVVM(Model-View-ViewModel)模式写前端,能把界面和业务逻辑拆开,这对做单元测试特别友好。
为什么MVVM适合单元测试
MVVM把界面(View)和数据逻辑(ViewModel)分开,View只负责显示,所有操作交给ViewModel处理。这样一来,测试的时候不用启动整个界面,直接对ViewModel写测试用例就行。比如你添加一个新设备到网络组,只需要验证ViewModel里的方法是否正确调用了后台接口,而不需要真去点按钮、等页面渲染。
举个实际场景:你在App里点击“断开设备”,理想情况是设备从列表消失,并通知路由器更新连接状态。如果ViewModel里有个disconnectDevice(id)方法,测试时就可以模拟网络请求成功或失败,检查状态字段是否正确更新。
写一个简单的测试例子
假设你的无线组网App用的是Jetpack Compose + ViewModel,可以这样写测试:
class NetworkViewModelTest {
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
private lateinit var viewModel: NetworkViewModel
@Before
fun setup() {
viewModel = NetworkViewModel(FakeNetworkRepository())
}
@Test
fun `断开设备后状态应标记为离线`() {
viewModel.disconnectDevice("device_001")
val state = viewModel.uiState.getOrAwaitValue()
val device = state.devices.find { it.id == "device_001" }
assertEqual(device?.status, DeviceStatus.OFFLINE)
}
}
这里用了一个假的数据仓库FakeNetworkRepository,避免测试时真的去发网络请求。这样跑测试快,也更容易控制各种边界情况,比如网络超时、设备不存在等。
测试覆盖常见问题
在真实使用中,用户可能在网络不稳定时反复操作。比如连续点击“重启路由器”,ViewModel应该能正确处理重复调用,避免发送多个请求。这类逻辑可以在测试里模拟:
@Test
fun `重复调用重启应防止多次请求`() {
var requestCount = 0
val spyRepo = object : NetworkRepository {
override fun restartRouter() {
requestCount++
}
}
viewModel = NetworkViewModel(spyRepo)
viewModel.restartRouter()
viewModel.restartRouter()
assertEqual(requestCount, 1) // 防抖机制生效
}
这种测试能帮你提前发现逻辑漏洞,而不是等用户投诉“点了好几下才重启”才去修。
把核心逻辑都加上单元测试后,每次改代码都能快速验证有没有引入新问题。特别是在团队协作中,一个人改了设备排序逻辑,另一个人写的测试马上就能告诉你会不会影响到连接状态更新。