使用 Mockk 和 Truth 在 Android 上进行单元测试(I):基础

介绍

本文介绍了如何开始使用MockkTruth框架为 Android 应用程序编写测试。

第一步

第一件事是build.gradle像往常一样将依赖项添加到应用程序模块文件中:

testImplementation "io.mockk:mockk:1.12.3"
testImplementation 'junit:junit:4.13.2'
testImplementation "com.google.truth:truth:1.1.3"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.1'

假设我们有一个 classCar和一个 class Engine,那么它们之间的关系就是每辆车都有一个引擎。因此,Car我们可以说类依赖于类Engine

要开始测试,我们只需在Android Studio中的 tests 文件夹中创建一个新类(注意,不是 androidTest,因为它用于仪器测试)。

注意:如果这是您第一次在 Android 上编写测试,您可以查看此文档

现在是的,让我们看看代码:

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 `Car with broken engine throws exception when turning on`() {
        every { engine.turnOn() } throws BrokenEngineException()
        assertThrows(BrokenEngineException::class.java) { car.turnOn() } 
    }
}

下一节将详细解释代码。

测试结构

setUp 和 tearDown 函数

我们找到的前两个函数是这些,它们也有注释@Before@After. 这已经告诉我们一些关于它们的性质,即它们分别在每次测试之前和之后执行。

通常,在函数setUp中,我们要做的是初始化我们的变量和我们想要测试的内容(从现在开始,我们将把它称为SUT:被测对象)。如您所见,我们将把依赖项初始化为模拟,即“哑”对象,它们将获得我们告诉它们的行为(我们将在下面解释如何)。我们将使用真值对象初始化 SUT,因为我们要测试的是真值对象。

至于函数tearDown,它没有太多历史,在这种情况下,我们删除所有要清理的模拟,仅此而已。在此功能中执行清洁任务。

测试的定义

每个单元测试都只是一个函数,它有一个标签@Test和一个名称来描述它的作用。

至于名字的写法,有很多,但在 Kotlin 中,一般都是写在两个反引号之间,并带有一个英文描述性短语。该短语通常描述 SUT、前提条件和预期结果。

在这个例子中,我们“确保”每辆发动机损坏的汽车 (SUT)(前提条件)在启动时都会抛出异常(预期结果)。

单元测试通常分为三个部分(一般来说,它不是 Kotlin 或 Android 独有的东西),称为三 A:Arrange、Act 和 Assert,翻译成西班牙语类似于组织先决条件、行动和确认结果。

安排:定义我们的模拟的行为

进入方法体,我们要写的第一部分是整理先决条件。这主要是为了建立我们的 mocks 的行为。由于它们是哑对象,如果我们尝试调用某个函数(例如,在 的情况下Engine,启动电机),我们将得到一个异常,因为我们没有定义在模拟中调用该函数时必须发生什么。

为此,通常使用everyand函数coEvery,这取决于我们要模拟的方法是否使用协程。语法完全相同,所以让我们看看使用的示例every

every { engine.turnOff() } just runs
every { engine.turnOn() } throws BrokenEngineException()
every { engine.getHorsePower() } returns 100

主要是我们要使用的三种方法。

  • 第一个用于返回的Unit方法,即不返回任何内容的方法,因此当它们被调用时,它们什么都不做,但不会抛出异常。
  • 使用第二个,以便在调用该方法时,它会抛出我们告诉它的异常。
  • 后者用于返回一些值的方法。

动作:调用 SUT 函数

第二步是调用 SUT 方法。简单地说,当我们已经建立了所有先决条件时,我们将对我们想要测试的方法进行正常调用,仅此而已。由于Truth框架的语法,这与最后一步一起完成了很多次,所以我不会突出任何其他内容。

断言:检查结果

最后,我们必须检查结果。这可以是多种多样的,因为我们想要检查的执行结果可以是任何性质的。通常,我们需要检查以下其中一项:

  • 调用某个函数。
  • 没有调用某个函数。
  • 函数的返回值与另一个预期结果匹配。
  • 一个函数抛出异常。
  • 函数返回的对象属于特定类型。

让我们看看如何使用我们可用的框架检查这些事情:

verify { engine.hasEnoughFuel() }
verify(exactly = 0) { engine.hasEnoughFuel() }

在第一个示例中,我们在第一种情况下检查的是函数被调用,但没有指定多少次。如果至少调用一次,则测试通过,否则,测试失败。在第二个例子中,我们做的是相反的,即检查函数没有被调用。这样,如果函数没有被调用,测试将通过,如果至少调用一次,测试将失败。

注意:就像它存在coEvery于模拟一样,它存在coVerify于测试使用协程的函数。

assertThat(car.getHorsePower()).isEqualTo(100)
assertThat(car.hasEnoughFuel()).isTrue()

在第二个例子中,我们检查的是调用某个函数的返回值是否等于我们期望的另一个值。

assertThrows(BrokenEngineException::class.java) { car.turnOn() }

这第三个示例将检查该方法在调用类方法BrokenEngineException时是否引发类型异常。turnOn``Car

assertThat(car.getEngineType()).isInstanceOf(DieselEngine::class.java)

最后,这将验证汽车的发动机是柴油的。这样,如果它是汽油、混合动力或电动发动机,测试就不会通过。

结论

这应该是与当今 Android 测试世界的第一次接触。这些框架极大地扩展了JUnit另一个最常用框架的功能,并极大地简化了测试语法。

本系列的其他文章将讲解如何编写更复杂的测试,测试类型LiveData的对象,类型的对象Flow,协程等。

作者:Programming journey
链接:https://cmhernandezdel.hashnode.dev/tests-unitarios-en-android-con-mockk-y-truth-i-fundamentos

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容