在为元素或系统设计测试策略时,有三个 相关测试方面:
- 范围:测试涉及多少代码?测试可以验证单个 整个应用,还是两者之间的某个位置通过 被测试范围被测试,通常称为测试对象 测试,同时还要测试被测系统或被测单元。
- 速度:测试的运行速度有多快?测试速度可能为毫秒级 至数分钟。
- 保真度:如何“真实”测试是什么?例如,如果部分代码 需要发出网络请求,测试代码是否会 还是会伪造结果?如果测试实际检测到 这意味着它具有更高的保真度。需要权衡的是, 测试可能需要较长的运行时间,如果网络出现故障,可能会导致错误,或者 可能成本高昂
查看要测试的内容,了解如何开始定义测试策略。
隔离和依赖项
测试一个元素或元素系统时,您可以在隔离环境中进行测试。对于 例如,要测试 ViewModel,您无需启动模拟器和启动界面 因为它不(或不应该)依赖于 Android 框架。
但是,被测对象可能依赖于其他对象才能正常运行。对于 ViewModel 可能依赖于数据存储库来工作。
当您需要为受测对象提供依赖项时,常见的做法是 创建测试替身(或测试对象)。测试替身是指 它们是应用中的组件,但它们是在测试中创建的, 提供特定行为或数据。它们的主要优势在于 测试更快、更简单
测试替身的类型
测试替身分为多种类型:
虚假 | 具有“有效”状态的测试替身类的实现,但其实现方式适合测试,但并不适合生产环境。
示例:内存中数据库。 虚假对象不需要模拟框架,并且是轻量级的。它们是首选的。 |
---|---|
模拟 | 测试替身,会按照您对其行为的编程来表现,并对互动行为有一定的预期。如果模拟的交互不符合您定义的要求,它们将无法通过测试。为了实现所有这些目的,您通常需要使用模拟框架来创建模拟。
示例:验证数据库中的某个方法是否正好调用一次。 |
存根 | 测试替身,会按照您对其行为的编程来行为,但对交互行为不作预期。通常使用模拟框架创建。为简单起见,最好使用虚假对象,而不是桩。 |
虚拟 | 已传递但不使用的测试替身,例如您只需要将其作为参数提供时。
示例:作为点击回调传递的空函数。 |
间谍 | 真实对象的封装容器,与模拟类似,还会跟踪一些其他信息。通常避免此类操作以增加复杂性。因此,虚假或模拟优于间谍。 |
阴影 | Robolectric 中使用的是假的。 |
使用虚构的示例
假设您要对依赖于接口的 ViewModel 进行单元测试
名为 UserRepository
,并向界面公开第一位用户的名称。您可以
通过实现相应接口并返回已知测试替身来创建虚假测试替身
数据。
object FakeUserRepository : UserRepository {
fun getUsers() = listOf(UserAlice, UserBob)
}
val const UserAlice = User("Alice")
val const UserBob = User("Bob")
此虚构 UserRepository
不需要依赖于本地和远程数据
正式版要使用的源代码文件位于测试源中
设置,不会随正式版应用一起提供。
![虚构依赖项可以返回已知数据,而无需依赖于远程数据源](https://developer.android.google.cn/static/training/testing/fundamentals/fake-deps.png?authuser=0000&hl=ro)
以下测试用于验证 ViewModel 是否正确公开了第一个用户 添加到视图。
@Test
fun viewModelA_loadsUsers_showsFirstUser() {
// Given a VM using fake data
val viewModel = ViewModelA(FakeUserRepository) // Kicks off data load on init
// Verify that the exposed data is correct
assertEquals(viewModel.firstUserName, UserAlice.name)
}
在单元测试中,用虚假对象替换 UserRepository
非常容易,因为
ViewModel 由测试人员创建。然而,要完全取代
大型测试中的任意元素。
替换组件和依赖项注入
如果测试无法控制受测系统的创建, 替换测试替身的组件变得更加复杂,并且需要 采用可测试的设计。
即使是大规模的端到端测试也可以受益于使用测试替身,例如 插桩界面测试,用于在应用中完成整个用户流的导航。在 在这种情况下,您可能需要将测试设为封闭。封闭测试可避免 所有外部依赖项,例如从互联网提取数据。这个 提高可靠性和性能
<ph type="x-smartling-placeholder">![](https://developer.android.google.cn/static/training/testing/fundamentals/bigtest.png?authuser=0000&hl=ro)
您可以将应用设计为手动实现这种灵活性,但我们建议您 使用 Hilt 等依赖项注入框架替换组件 测试时的表现请参阅 Hilt 测试指南。
Robolectric
在 Android 上,您可以使用 Robolectric 框架, 提供了一种特殊类型的测试替身。借助 Robolectric, 您的工作站或持续集成环境中它使用 常规 JVM,没有模拟器或设备。可以模拟视图的膨胀, 资源加载,以及 Android 框架的其他部分,包括测试替身 称为阴影。
Robolectric 是一个模拟器,因此不应取代简单的单元测试,也不应使用 以进行兼容性测试它可以提高速度并降低成本 某些情况下的保真度较低进行界面测试的一个好方法是 同时兼容 Robolectric 和插桩测试,还可决定何时运行 具体取决于对功能或兼容性进行测试的需求。Espresso 和 和 Compose 测试可以在 Robolectric 上运行。