单元测试是什么?怎么测?怎么判断测试结果?对于很多刚接触测试的同学,特别是代码能力较弱或作为初级测试工程师的小伙伴,可能对单元测试并不熟悉。你可能面试的时候知道一些概念,例如什么unittest、JUnit框架,但在实际操作中却缺乏具体的印象。本文将通过常见编程语言中的单元测试案例,为你提供详细的实操指导,帮助你深入理解单元测试的实现与应用。
文章目录
一、什么是单元测试?
单元测试是针对代码中最小可测试单元(如函数、方法、类)的自动化测试,目的是验证其行为是否符合预期。它的核心特点是:
- 隔离性:每个测试用例独立运行,不依赖外部资源(如数据库、网络)。
- 快速反馈:测试执行速度快,适合在开发过程中频繁运行。
- 预防 Bug:通过早期发现问题,降低修复成本。
单元测试 vs 功能测试
特性 | 单元测试 | 功能测试 |
---|---|---|
测试粒度 | 代码的最小单元(函数/方法) | 完整的业务功能 |
执行速度 | 毫秒级 | 秒级或分钟级 |
依赖 | 无外部依赖(Mock/Stub) | 可能需要真实环境 |
二、常见的单元测试类型
-
正常情况测试
验证函数在合法输入下的正确输出。
示例:add(2, 3)
应该返回5
。 -
边界条件测试
测试输入值的极端情况。
示例:列表索引为0
或len(list)-1
时的行为。 -
异常情况测试
验证函数在非法输入时是否抛出预期异常。
示例:传递None
作为参数时是否抛出TypeError
。 -
状态验证测试
测试函数是否修改了对象的状态。
示例:调用list.append()
后列表长度是否增加。
三、Python 单元测试实战(使用 unittest
)
示例代码:计算器函数
# calculator.py
def add(a, b):
return a + b
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero!")
return a / b
单元测试代码
# test_calculator.py
import unittest
from calculator import add, divide
class TestCalculator(unittest.TestCase):
# 正常情况测试
def test_add_positive_numbers(self):
self.assertEqual(add(2, 3), 5) # 断言预期结果
# 边界测试
def test_add_zero(self):
self.assertEqual(add(0, 0), 0)
# 异常测试
def test_divide_by_zero(self):
with self.assertRaises(ValueError): # 捕获预期异常
divide(10, 0)
if __name__ == '__main__':
unittest.main() # 运行测试
运行测试
python -m unittest test_calculator.py
比如说 我们要测试 2+3=5 是否计算正确 可以在test_add_positive_numbers(self) 函数里输入函数参数预期值:
self.assertEqual(add(2, 3), 5) # 断言预期结果
运行完毕测试结果通过 则显示ok
那怎么判断,结果出错呢?假如我们就设定 2+3=6 是正确的,设置 self.assertEqual(add(2,3),6),则单元测试就会判断原来的add函数出错返回给我们Error提示 5!=6 即 系统结果不符合测试结果!
四、Java 单元测试实战(使用 JUnit 5
+ Maven
)
示例代码:计算器类
// Calculator.java
public class Calculator {
public static int add(int a, int b) {
return a + b;
}
public static double divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("Cannot divide by zero!");
}
return (double) a / b;
}
}
单元测试代码
// CalculatorTest.java
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
// 正常情况测试
@Test
void testAddPositiveNumbers() {
assertEquals(5, Calculator.add(2, 3)); // 注意参数顺序:预期值在前
}
// 边界测试
@Test
void testAddZero() {
assertEquals(0, Calculator.add(0, 0));
}
// 异常测试
@Test
void testDivideByZero() {
Exception exception = assertThrows(
IllegalArgumentException.class,
() -> Calculator.divide(10, 0) // 使用Lambda表达式触发异常
);
assertTrue(exception.getMessage().contains("Cannot divide by zero!"));
}
}
Maven 依赖
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
运行测试
在 IDE 中右键点击测试类运行,或使用 Maven 命令:
mvn test
五、关键技巧
-
命名规范
Python:测试方法名以test_
开头
Java:方法名自由,但建议使用Test
后缀的类名(如CalculatorTest
) -
断言方法
操作 Python ( unittest
)Java ( JUnit 5
)相等断言 assertEqual(a, b)
assertEquals(a, b)
异常断言 assertRaises(Exception)
assertThrows(Exception)
-
测试覆盖率工具
Python:coverage
库
Java:JaCoCo 或 Cobertura