编写第一个测试:@Test 注解与基本断言

我们要从零开始写一个真正的测试了。你可能会想:「不就是加个注解嘛,有什么好讲的?」

嗯,我当年也这么觉得。直到有一次我在 CI 上跑测试,发现一个测试方法根本没执行,排查了半小时才发现——我忘了加 @Test。所以别看它简单,细节里全是坑。

1. @Test 注解——测试的入口

@Test 来自 kotlin.test 包,它告诉测试框架「这个方法是一个测试用例」。被标注的方法必须满足三个条件:

  • 返回值类型必须是 Unit(也就是不返回任何东西)
  • 不能有参数
  • 方法名不能是 test 开头?——其实没有这个限制,但按惯例我们通常写成 testXxx 或 shouldXxx
import kotlin.test.Test

class CalculatorTest {

    @Test
    fun testAddition() {
        // 这里写测试逻辑
    }
}
如果你用 IntelliJ IDEA,直接在类名或方法名左侧点击绿色箭头就能运行。我个人习惯给测试类名加一个 Test 后缀,统一好找。

2. 基本断言——让测试「说话」

光有 @Test 还不够,你得告诉框架「预期结果是什么」。断言就是干这个活的。Kotlin 的 kotlin.test 提供了几个常用函数,我列个表格:

断言函数 作用 示例
assertEquals(expected, actual) 判断两个值相等(通过 equals 比较) assertEquals(4, calculator.add(2, 2))
assertNotEquals(illegal, actual) 判断两个值不相等 assertNotEquals(5, calculator.add(2, 2))
assertTrue(condition) 判断条件为 true assertTrue(list.isEmpty())
assertFalse(condition) 判断条件为 false assertFalse(list.isNotEmpty())
assertNull(value) 判断值为 null assertNull(cache.get("not-exist"))
assertNotNull(value) 判断值非 null assertNotNull(viewModel.user)
assertSame(expected, actual) 判断两个引用指向同一个对象(引用比较) assertSame(singleton, Singleton.instance)

大部分情况下 assertEquals + assertTrue 已经能覆盖 90% 的场景。我建议你优先用 assertEquals,因为它失败时能打印出期望值和实际值,调试起来很方便。

3. 写一个完整的测试

我们拿一个简单的减法函数来练手:

class Calculator {
    fun subtract(a: Int, b: Int): Int {
        return a - b
    }
}

// 测试类
class CalculatorTest {

    private val calculator = Calculator()

    @Test
    fun testSubtract() {
        val result = calculator.subtract(10, 3)
        assertEquals(7, result)
    }

    @Test
    fun testSubtractNegativeResult() {
        val result = calculator.subtract(3, 10)
        assertEquals(-7, result)
    }

    @Test
    fun testSubtractWithZero() {
        val result = calculator.subtract(5, 0)
        assertEquals(5, result)
    }
}

运行所有测试,如果全部通过你会看到绿色提示。有一个失败就会显示红色,并且告诉你哪一行、期望值和实际值分别是什么。

我曾经写过一个测试,assertEquals 里把期望值和实际值写反了——第一个参数写成了实际值。虽然结果一样,但报错信息会完全反着显示,排查起来非常痛苦。所以麻烦你养成习惯:第一个参数写期望值,第二个参数写实际值。

4. 知识结构一览

下面这张图把整个流程串了起来,你可以把它当作大脑地图:

编写第一个测试核心流程 1. 编写测试类 2. 添加 @Test 注解 3. 调用被测方法 4. 使用断言验证结果 5. 运行测试(绿色/红色) 常用断言 • assertEquals • assertTrue • assertNull • assertNotNull • assertSame

你跟着这个流程走一遍,基本就能写出第一个能用的测试。注意每个节点都有对应的代码实现,没什么黑魔法。

5. 额外的小贴士

  • 测试方法名要能表达意图:比如 shouldReturnSevenWhenSubtractTenMinusThree 虽然长,但失败时一眼就能看出哪里逻辑错了。
  • 一个测试方法只测一个逻辑点:不要在同一个 @Test 方法里断言好几个不相关的场景,否则第一个失败后面就全跳过了。
  • 及时清理测试数据:如果测试修改了全局状态,记得在 @After 里恢复。不过那是后面章节的内容了,今天先不用操心。
小结一下:@Test 负责标记,「断言」负责验证。两者结合就是最基础的测试骨架。你可以在任何 Kotlin 项目中用同样的模式开始写测试,不管它是不是回归测试。