Appearance
Codelab: 参数化边界测试
预计时间:15 分钟
学习目标
完成本教程后,你将能够:
- 使用边界类型自动生成测试用例
- 使用组合策略减少测试数量
- 使用显式用例精确控制测试
场景描述
你正在开发一个数据验证库,需要测试各种边界情况:
- 字节范围验证(0-255)
- 坐标边界检查
- 数据类型转换
手动编写每个边界测试太繁琐了。
解决方案:使用参数化测试自动生成用例。
步骤 1: 创建项目结构
bash
mkdir -p validator-demo/{src,include,build,tests}
cd validator-demo步骤 2: 编写验证函数
创建 include/validator.h:
c
#ifndef VALIDATOR_H
#define VALIDATOR_H
// 验证字节值(0-255有效)
int is_valid_byte(int value);
// 验证坐标(0到max-1有效)
int is_in_bounds(int x, int y, int max_x, int max_y);
// 截断到字节范围
int clamp_byte(int value);
// 标准化布尔值
int normalize_bool(int value);
#endif创建 src/validator.c:
c
#include "validator.h"
int is_valid_byte(int value) {
return (value >= 0 && value <= 255) ? 1 : 0;
}
int is_in_bounds(int x, int y, int max_x, int max_y) {
return (x >= 0 && x < max_x && y >= 0 && y < max_y) ? 1 : 0;
}
int clamp_byte(int value) {
if (value < 0) return 0;
if (value > 255) return 255;
return value;
}
int normalize_bool(int value) {
return value != 0 ? 1 : 0;
}步骤 3: 编译源代码
bash
gcc -c src/validator.c -o build/validator.o -Iinclude步骤 4: 使用边界类型
创建 tests/test_validator.c:
c
#include "validator.h"
/*
* 设计说明:使用 uint8 边界值测试字节验证
* 预期结果:0-255有效,-1和256无效
*/
__attribute__((test_method, params(n = boundary(uint8))))
int test_valid_byte_boundary(int n) {
int result = is_valid_byte(n);
int expected = (n >= 0 && n <= 255) ? 1 : 0;
return result == expected;
}
// includes: -I../include运行测试:
bash
anvil输出:
Discovered 8 test cases in 1 file.
test_validator::test_valid_byte_boundary[n=0] ...... PASSED
test_validator::test_valid_byte_boundary[n=1] ...... PASSED
test_validator::test_valid_byte_boundary[n=127] .... PASSED
test_validator::test_valid_byte_boundary[n=128] .... PASSED
test_validator::test_valid_byte_boundary[n=254] .... PASSED
test_validator::test_valid_byte_boundary[n=255] .... PASSED
test_validator::test_valid_byte_boundary[n=-1] ..... PASSED
test_validator::test_valid_byte_boundary[n=256] .... PASSED
All 8 tests passed.一个函数,自动生成 8 个测试用例!
步骤 5: 使用显式值列表
在 tests/test_validator.c 中添加:
c
/*
* 设计说明:使用自定义值列表测试
* 预期结果:涵盖典型边界点
*/
__attribute__((test_method, params(value = {-100, -1, 0, 1, 127, 128, 254, 255, 256, 1000})))
int test_valid_byte_explicit(int value) {
int result = is_valid_byte(value);
int expected = (value >= 0 && value <= 255) ? 1 : 0;
return result == expected;
}步骤 6: 多参数笛卡尔积
c
/*
* 设计说明:测试二维坐标验证(笛卡尔积)
* 预期结果:坐标在 [0, 100) 范围内有效
*/
__attribute__((test_method,
params(x = {-1, 0, 50, 99, 100}, y = {-1, 0, 50, 99, 100})))
int test_bounds_cartesian(int x, int y) {
int result = is_in_bounds(x, y, 100, 100);
int expected = (x >= 0 && x < 100 && y >= 0 && y < 100) ? 1 : 0;
return result == expected;
}这会生成 5×5=25 个测试用例。
步骤 7: 使用 Pairwise 策略
c
/*
* 设计说明:使用 Pairwise 减少组合数量
* 预期结果:覆盖所有两两组合
*/
__attribute__((test_method,
params(x = {-1, 0, 50, 99, 100}, y = {-1, 0, 50, 99, 100}),
strategy(pairwise)))
int test_bounds_pairwise(int x, int y) {
int result = is_in_bounds(x, y, 100, 100);
int expected = (x >= 0 && x < 100 && y >= 0 && y < 100) ? 1 : 0;
return result == expected;
}Pairwise 策略会显著减少测试用例数量。
步骤 8: 使用 Zip 策略
c
/*
* 设计说明:使用 Zip 测试截断函数
* 预期结果:输入和预期输出一一对应
*/
__attribute__((test_method,
params(input = {-100, -1, 0, 128, 255, 256, 1000},
expected = {0, 0, 0, 128, 255, 255, 255}),
strategy(zip)))
int test_clamp_byte_zip(int input, int expected) {
return clamp_byte(input) == expected;
}生成 7 个测试用例,每个输入对应一个预期输出。
步骤 9: 使用 cases() 语法
c
/*
* 设计说明:使用 cases 语法精确控制用例
* 预期结果:每个用例独立验证
*/
__attribute__((test_method, cases(
(-100, 0),
(-1, 0),
(0, 0),
(128, 128),
(255, 255),
(256, 255),
(1000, 255)
)))
int test_clamp_byte_cases(int input, int expected) {
return clamp_byte(input) == expected;
}步骤 10: 测试布尔边界
c
/*
* 设计说明:测试布尔标准化的边界值
* 预期结果:0->0, 非零->1
*/
__attribute__((test_method, params(value = boundary(bool))))
int test_normalize_bool_boundary(int value) {
int result = normalize_bool(value);
int expected = (value != 0) ? 1 : 0;
return result == expected;
}步骤 11: 运行所有测试
bash
anvil查看生成的测试用例数量和结果。
知识点总结
你已学会:
| 技能 | 说明 |
|---|---|
boundary(type) | 自动生成边界值 |
params(x = {...}) | 显式值列表 |
| 笛卡尔积 | 默认策略,所有组合 |
strategy(pairwise) | 减少组合数量 |
strategy(zip) | 按索引配对 |
cases((...), ...) | 精确控制每个用例 |
策略选择指南
| 场景 | 推荐策略 |
|---|---|
| 单参数边界测试 | boundary(type) |
| 2个参数,值少 | 笛卡尔积(默认) |
| 3+个参数 | strategy(pairwise) |
| 输入/输出配对 | strategy(zip) 或 cases() |
完整测试文件
最终的 tests/test_validator.c:
c
#include "validator.h"
// 边界类型测试
__attribute__((test_method, params(n = boundary(uint8))))
int test_valid_byte_boundary(int n) {
int result = is_valid_byte(n);
int expected = (n >= 0 && n <= 255) ? 1 : 0;
return result == expected;
}
// 显式值列表
__attribute__((test_method, params(value = {-100, -1, 0, 1, 127, 128, 254, 255, 256, 1000})))
int test_valid_byte_explicit(int value) {
int result = is_valid_byte(value);
int expected = (value >= 0 && value <= 255) ? 1 : 0;
return result == expected;
}
// 笛卡尔积
__attribute__((test_method,
params(x = {-1, 0, 50, 99, 100}, y = {-1, 0, 50, 99, 100})))
int test_bounds_cartesian(int x, int y) {
int result = is_in_bounds(x, y, 100, 100);
int expected = (x >= 0 && x < 100 && y >= 0 && y < 100) ? 1 : 0;
return result == expected;
}
// Pairwise 策略
__attribute__((test_method,
params(x = {-1, 0, 50, 99, 100}, y = {-1, 0, 50, 99, 100}),
strategy(pairwise)))
int test_bounds_pairwise(int x, int y) {
int result = is_in_bounds(x, y, 100, 100);
int expected = (x >= 0 && x < 100 && y >= 0 && y < 100) ? 1 : 0;
return result == expected;
}
// Zip 策略
__attribute__((test_method,
params(input = {-100, -1, 0, 128, 255, 256, 1000},
expected = {0, 0, 0, 128, 255, 255, 255}),
strategy(zip)))
int test_clamp_byte_zip(int input, int expected) {
return clamp_byte(input) == expected;
}
// cases 语法
__attribute__((test_method, cases(
(-100, 0), (-1, 0), (0, 0), (128, 128), (255, 255), (256, 255), (1000, 255)
)))
int test_clamp_byte_cases(int input, int expected) {
return clamp_byte(input) == expected;
}
// 布尔边界
__attribute__((test_method, params(value = boundary(bool))))
int test_normalize_bool_boundary(int value) {
int result = normalize_bool(value);
int expected = (value != 0) ? 1 : 0;
return result == expected;
}
// includes: -I../include完成所有 Codelab
恭喜!你已掌握 Anvil 的核心功能:
- 基本测试编写
- Mock 隔离测试
- 参数化边界测试
现在可以开始在你的项目中使用 Anvil 了!