跳到主要内容

XUnit 测试框架 - GS语言版本

一个基于GS语言的现代化单元测试框架,参考.NET xunit框架的设计理念,支持TestSuite结构化管理和基准测试。

主要特性

  • 🔍 自动测试发现:基于命名约定自动发现测试用例
  • 📁 TestSuite结构:使用TestSuite包装测试,每个测试代码文件对应一个TestSuite
  • 🧩 弱化Suite概念:每个测试用例都有suite属性,默认为空字符串
  • 📊 多种测试类型:支持Fact、Theory(参数化)、Benchmark测试
  • 🛠️ 自动Setup/Teardown:基于命名约定自动绑定suite级别的setup/teardown函数
  • ⚡ 高性能:支持并行测试执行(可选)
  • 📈 基准测试:内置基准测试支持,包含性能分析
  • 🎯 灵活配置:丰富的配置选项和命名约定

快速开始

1. 基本测试用例

// 定义测试套件名称列表(可选)
public array get_suite_names()
{
return ["用户管理", "产品管理", "系统工具"];
}

// 自动归类到 "user" suite
public void test_user_creation()
{
// 测试用例实现
string username = "testuser";
xassert.not_empty(username, "用户名不能为空");
}

// 没有明确suite的测试(suite为空字符串)
public void test_utility_functions()
{
// 测试用例实现
string result = helper_function("test");
xassert.equal("TEST", result, "应该转换为大写");
}

2. Suite级别的Setup/Teardown

// 用户suite的setup函数
public void user_setup()
{
printf("初始化用户测试数据\n");
// 准备测试数据
}

// 用户suite的teardown函数
public void user_teardown()
{
printf("清理用户测试数据\n");
// 清理测试数据
}

3. 参数化测试

// 自动归类到 "login" suite
public void theory_login_validation(string username, string password, bool expected)
{
bool result = validate_login(username, password);
xassert.equal(expected, result, "登录验证结果不匹配");
}

// 测试数据提供者
public array theory_login_validation_data()
{
return [
["admin", "password123", true],
["user", "wrongpass", false],
["", "password", false]
];
}

4. 基准测试

// 自动归类到 "performance" suite
public void bench_performance_string_operations()
{
string result = "";
for (int i = 0; i < 1000; i++)
{
result += "test";
}
}

// 指定迭代次数的基准测试
public void benchmark_performance_array_ops_iter_5000()
{
array data = [];
for (int i = 0; i < 100; i++)
{
data.push_back(i);
}
}

5. 运行测试

// 在你的测试文件中
void create()
{
// 配置测试框架
xunit.configure({"verbose": true});

// 自动发现测试用例
int count = xunit.discover_tests_by_naming_convention(this_object());
printf("发现 %d 个测试用例\n", count);

// 运行所有测试
map results = xunit.run_all_tests({});

// 显示结果
printf("通过: %d, 失败: %d, 跳过: %d\n",
results["summary"]["passed"],
results["summary"]["failed"],
results["summary"]["skipped"]);
}

TestSuite结构

TestSuite概念

  • TestSuite:包装一个测试套件,对应一个测试代码文件
  • TestCase:每个测试用例都有suite属性,默认为空字符串
  • TestSuite执行:测试以TestSuite为单位依次执行
  • names属性:TestSuite中存在names属性,用于定义当前套件的名称列表

TestSuite结构图

TestSuite (test_file.gs)
├── names: ["用户管理", "产品管理"]
├── test_cases: [
│ ├── TestCase { name: "test_user_login", suite: "user" }
│ ├── TestCase { name: "test_product_search", suite: "product" }
│ └── TestCase { name: "test_utility_func", suite: "" }
└── ]

get_suite_names函数

如果测试代码文件中存在get_suite_names函数,框架会自动调用它来获取TestSuite的names属性:

public array get_suite_names()
{
return ["用户管理", "产品管理", "系统工具"];
}

命名约定

测试函数命名

  • Fact测试test_*fact_*should_*
  • Theory测试theory_*param_test_*
  • Benchmark测试bench_*benchmark_*perf_*

Suite自动识别

测试函数会根据以下规则自动分配到suite:

  • test_user_login() → "user" suite
  • theory_product_search() → "product" suite
  • bench_performance_query() → "performance" suite
  • test_utility_helper() → "" suite (空字符串)

Setup/Teardown函数命名

  • Setup函数{suite_name}_setupsetup_{suite_name}
  • Teardown函数{suite_name}_teardownteardown_{suite_name}

测试用例属性

每个测试用例都有以下属性:

  • name: 测试函数名
  • type: 测试类型(fact、theory、benchmark)
  • suite: suite名称,默认为空字符串
  • suite_setup: suite级别的setup函数(如果有)
  • suite_teardown: suite级别的teardown函数(如果有)

API 参考

核心函数

// 配置测试框架
xunit.configure(map config);

// 发现测试用例(会创建TestSuite)
int discover_tests_by_naming_convention(object test_object);

// 运行所有测试(以TestSuite为单位执行)
map run_all_tests(map options);

// 运行指定suite的测试
map run_suite_tests(array suite_names, map options);

// 运行指定TestSuite
map run_test_suite(TestSuite test_suite, map options);

// 运行基准测试
map run_benchmark_tests(map options);

// 获取测试统计信息
map get_test_statistics();

// 获取可用的suite名称
array get_suite_names();

// 获取所有TestSuite
array get_all_test_suites();

TestSuite类

// 创建TestSuite
TestSuite test_suite = TestSuite.new(test_object, source_file);

// 设置suite名称列表
test_suite.set_names(array names);

// 添加测试用例
test_suite.add_test_case(TestCase test_case);

// 获取测试用例
array test_cases = test_suite.get_test_cases();

// 获取suite名称
array names = test_suite.get_names();

TestCase类

// 创建TestCase
TestCase test_case = TestCase.new(name, type, func, test_object);

// 设置suite
test_case.set_suite(string suite_name);

// 设置setup/teardown函数
test_case.set_suite_functions(function setup_func, function teardown_func);

断言函数

// 基本断言
xassert.equal(expected, actual, message);
xassert.not_equal(expected, actual, message);
xassert.is_true(condition, message);
xassert.is_false(condition, message);
xassert.not_null(value, message);
xassert.null(value, message);

// 数组断言
xassert.array_length(array, expected_length, message);
xassert.array_contains(array, value, message);
xassert.array_not_contains(array, value, message);

// 数值断言
xassert.greater_than(actual, expected, message);
xassert.less_than(actual, expected, message);
xassert.in_range(actual, min, max, message);

文件结构

xunit/
├── src/
│ ├── xunit.gs # 核心框架,包含TestSuite和TestCase类
│ ├── test_discoverer.gs # 测试发现器,支持TestSuite创建
│ ├── test_runner.gs # 测试运行器
│ ├── test_reporter.gs # 测试报告器
│ └── xassert.gs # 断言库
├── sample/
│ └── test_suite_simplified.gs # 示例测试文件
└── README.md # 说明文档

示例文件

完整示例请查看 sample/test_suite_simplified.gs,它展示了:

  • 如何使用get_suite_names函数
  • 自动suite分组
  • Suite级别的setup/teardown
  • 各种类型的测试用例
  • 基准测试示例

版本更新

v2.0.0 - TestSuite结构重构

  • 新增:TestSuite类包装测试套件
  • 新增:get_suite_names函数支持
  • 优化:以TestSuite为单位执行测试
  • 移除:suite_grouping_rules配置项
  • 改进:更清晰的测试组织结构

v1.0.0 - 基础版本

  • 基本的测试发现和执行功能
  • 支持Fact、Theory、Benchmark测试类型
  • 自动化的suite分组