Skip to content

显式用例

使用 cases() 语法精确控制每个测试用例。

基本语法

c
__attribute__((test_method, cases((值1, 值2, ...), (值1, 值2, ...), ...)))
int test_function(参数1, 参数2, ...) {
    // 测试逻辑
}

简单示例

c
/*
 * 设计说明:测试字节截断函数
 * 预期结果:超出范围的值被截断到边界
 */
__attribute__((test_method, cases(
    (-100, 0),
    (-1, 0),
    (0, 0),
    (128, 128),
    (255, 255),
    (256, 255),
    (1000, 255)
)))
int test_clamp_byte(int input, int expected) {
    return clamp_byte(input) == expected;
}

生成 7 个测试用例:

test_clamp_byte[input=-100, expected=0]
test_clamp_byte[input=-1, expected=0]
test_clamp_byte[input=0, expected=0]
test_clamp_byte[input=128, expected=128]
test_clamp_byte[input=255, expected=255]
test_clamp_byte[input=256, expected=255]
test_clamp_byte[input=1000, expected=255]

与 params + strategy(zip) 对比

cases()params() + strategy(zip) 功能相似:

c
__attribute__((test_method, cases(
    (1, 1),
    (2, 4),
    (3, 9)
)))
int test_square(int input, int expected) {
    return math_square(input) == expected;
}
c
__attribute__((test_method,
    params(input = {1, 2, 3}, expected = {1, 4, 9}),
    strategy(zip)))
int test_square(int input, int expected) {
    return math_square(input) == expected;
}

cases() 的优势:

  • 输入和预期输出放在一起,更直观
  • 适合复杂的测试数据
  • 易于添加和修改用例

多参数用例

c
/*
 * 设计说明:测试三数之和
 * 预期结果:返回三个数的和
 */
__attribute__((test_method, cases(
    (0, 0, 0, 0),
    (1, 2, 3, 6),
    (-1, 1, 0, 0),
    (100, 200, 300, 600),
    (-50, -50, 100, 0)
)))
int test_sum3(int a, int b, int c, int expected) {
    return sum3(a, b, c) == expected;
}

错误码测试

c
/*
 * 设计说明:测试除法函数错误处理
 * 预期结果:除零返回错误码,正常返回商
 */
__attribute__((test_method, cases(
    (10, 2, 5, 0),      // 正常除法
    (10, 3, 3, 0),      // 整数除法
    (0, 5, 0, 0),       // 零除以非零
    (10, 0, 0, -1),     // 除以零错误
    (-10, 2, -5, 0)     // 负数除法
)))
int test_safe_divide(int a, int b, int expected_result, int expected_error) {
    int error = 0;
    int result = safe_divide(a, b, &error);

    if (expected_error != 0) {
        return error == expected_error;
    }
    return result == expected_result && error == 0;
}

字符串测试

c
/*
 * 设计说明:测试字符串长度函数
 * 预期结果:返回正确的长度
 */
__attribute__((test_method, cases(
    ("", 0),
    ("a", 1),
    ("hello", 5),
    ("hello world", 11)
)))
int test_strlen(const char *str, int expected) {
    return my_strlen(str) == expected;
}

边界值 + 显式用例

可以在同一个测试文件中结合使用:

c
// 使用边界类型进行广泛覆盖
__attribute__((test_method, params(n = boundary(uint8))))
int test_byte_boundary(int n) {
    return is_valid_byte(n) == (n >= 0 && n <= 255);
}

// 使用显式用例测试特殊情况
__attribute__((test_method, cases(
    (0, 1),
    (255, 1),
    (-1, 0),
    (256, 0)
)))
int test_byte_explicit(int value, int expected) {
    return is_valid_byte(value) == expected;
}

完整示例

c
#include "parser.h"

/*
 * 设计说明:测试 HTTP 状态码解析
 * 预期结果:返回正确的状态码类别
 */
__attribute__((test_method, cases(
    (200, STATUS_OK),
    (201, STATUS_OK),
    (204, STATUS_OK),
    (301, STATUS_REDIRECT),
    (302, STATUS_REDIRECT),
    (400, STATUS_CLIENT_ERROR),
    (401, STATUS_CLIENT_ERROR),
    (403, STATUS_CLIENT_ERROR),
    (404, STATUS_CLIENT_ERROR),
    (500, STATUS_SERVER_ERROR),
    (502, STATUS_SERVER_ERROR),
    (503, STATUS_SERVER_ERROR)
)))
int test_status_category(int code, int expected_category) {
    return get_status_category(code) == expected_category;
}

/*
 * 设计说明:测试 URL 解析
 * 预期结果:正确提取主机名
 */
__attribute__((test_method, cases(
    ("http://example.com", "example.com"),
    ("https://www.google.com/search", "www.google.com"),
    ("http://localhost:8080", "localhost"),
    ("https://api.github.com/repos", "api.github.com")
)))
int test_parse_host(const char *url, const char *expected_host) {
    char host[256];
    parse_host(url, host, 256);
    return strcmp(host, expected_host) == 0;
}

/*
 * 设计说明:测试日期解析
 * 预期结果:正确解析年月日
 */
__attribute__((test_method, cases(
    ("2024-01-15", 2024, 1, 15, 0),
    ("2023-12-31", 2023, 12, 31, 0),
    ("2024-02-29", 2024, 2, 29, 0),    // 闰年
    ("2023-02-29", 0, 0, 0, -1),       // 非闰年,无效
    ("invalid", 0, 0, 0, -1)           // 格式错误
)))
int test_parse_date(const char *str, int exp_y, int exp_m, int exp_d, int exp_err) {
    int y, m, d;
    int err = parse_date(str, &y, &m, &d);

    if (exp_err != 0) {
        return err == exp_err;
    }
    return y == exp_y && m == exp_m && d == exp_d;
}

// includes: -I../include

最佳实践

  1. 输入和预期放一起:使用 cases() 而非分开的 params()
  2. 覆盖边界情况:包含边界值、错误情况
  3. 注释说明:每个用例的目的
  4. 合理数量:通常 5-15 个用例足够

本页面内容遵循 Luna 软件源代码授权条款 (LSLA) 发布