使用 Mockk 和 Truth 在 Android 中进行单元
介绍
本文解释了使用Mockk和Truth库在 Android 上进行单元测试的更高级的模拟概念。
测试模拟类字段的变化
很多时候,由于某种原因,我们需要检查当我们调用SUT(被测对象)方法时,其依赖项之一(我们已经模拟)中的某些内容发生了变化。
让我们看下面的例子:继续类Car
和Engine
前面的例子(其中每辆车都依赖于一个引擎),我们可能想要验证,当我们启动汽车时,引擎进入“on”状态。
但是,我们没有这样的对象Engine
,而是它的模拟对象,因此如果我们尝试获取 的值isStarted
,我们将在测试中遇到异常。为此,使用了关键字capture
:
class CarTest {
lateinit var engine: Engine
lateinit var car: Car
@Before
fun setUp() {
engine = mockk<Engine>()
car = Car (engine)
}
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `Engine turns on when car turns on`() {
val engineStarted = slot<Boolean>()
every { engine.started = capture(engineStarted) } just runs
car.start()
assertThat(engineStarted.captured).isTrue()
}
}
也就是说,与任何其他模拟方法一样,如果要使用它们,我们实际上需要定义其 setter 的行为。并且通过关键字capture
我们可以知道他们在执行该方法后将获得的值。
同样,如果我们只需要让 setter 工作但我们并不特别关心值,我们可以执行以下操作:
every { engine.started = any() } just runs
这样做很重要,因为如果使用了 setter 而我们还没有定义它的行为,测试会抛出异常。
使用静态类和伴随对象进行测试
有时我们可能需要在代码中使用静态类,例如库Math
或非常常见的Log
Android 类。如果我们的代码使用了一些静态类,我们会看到测试中会抛出一个异常,说明我们没有模拟它的行为。
但是,我们不能调用该函数mockk
,因为我们不能实例化一个静态类。那么,我们该怎么做呢?
答案很简单,我们可以使用mockkStatic
:
class CarTest {
@Before
fun setUp() {
mockkStatic(Log::class)
every { Log.d(any(), any()) } just runs
}
@After
fun tearDown() {
unmockkStatic()
}
}
由于companion objects
Kotlin 是静态类的 Java 等价物,我们可能倾向于认为同样的东西适用于它们。然而,static
在 Kotlin 中并没有真正存在的概念,虽然它们看起来很像,companion objects
但它们也不是静态类,所以这种方法对我们不起作用。
同样,该库为此提供了一个功能,它是mockkObject
:
@Before
fun setUp() {
mockkObject(MyCompanionObject.Companion)
every { MyCompanionObject.doSomething() } just runs
}
通过我们在本系列的上一篇文章和这篇文章中学到的知识,我们实际上知道如何创建几乎任何东西的模拟。在接下来的文章中,我们将使用更复杂的 Kotlin 和 Android 概念测试,例如协程、流、LiveData...