Browse Source

add test docs

ruki 3 weeks ago
parent
commit
58cc69b8ff
4 changed files with 798 additions and 0 deletions
  1. 1 0
      docs/config.ts
  2. 398 0
      docs/guide/basic-commands/run-tests.md
  3. 1 0
      docs/zh/config.ts
  4. 398 0
      docs/zh/guide/basic-commands/run-tests.md

+ 1 - 0
docs/config.ts

@@ -153,6 +153,7 @@ function guideSidebar(): DefaultTheme.SidebarItem[] {
         { text: 'Build Configuration', link: 'basic-commands/build-configuration' },
         { text: 'Build Targets', link: 'basic-commands/build-targets' },
         { text: 'Run Targets', link: 'basic-commands/run-targets' },
+        { text: 'Run Tests', link: 'basic-commands/run-tests' },
         { text: 'Install and Uninstall', link: 'basic-commands/install-and-uninstall' },
         { text: 'Pack Programs', link: 'basic-commands/pack-programs' },
         { text: 'Cross Compilation', link: 'basic-commands/cross-compilation' },

+ 398 - 0
docs/guide/basic-commands/run-tests.md

@@ -0,0 +1,398 @@
+# Run tests {#run-tests}
+
+Xmake provides a built-in `xmake test` command for running unit tests and test cases. Starting from version 2.8.5, you can configure test cases through `add_tests` on targets that need testing, and then automatically execute all tests.
+
+This provides great convenience for automated testing, and even if a target is set to `set_default(false)`, xmake will still automatically compile it when executing tests and then run all tests.
+
+## Command format
+
+```sh
+$ xmake test [options] [target/testname]
+```
+
+## Basic usage
+
+### Configure test cases
+
+First, we need to configure test cases for the target using `add_tests`:
+
+```lua
+add_rules("mode.debug", "mode.release")
+
+for _, file in ipairs(os.files("src/test_*.cpp")) do
+    local name = path.basename(file)
+    target(name)
+        set_kind("binary")
+        set_default(false)
+        add_files("src/" .. name .. ".cpp")
+        add_tests("default")
+        add_tests("args", {runargs = {"foo", "bar"}})
+        add_tests("pass_output", {trim_output = true, runargs = "foo", pass_outputs = "hello foo"})
+        add_tests("fail_output", {fail_outputs = {"hello2 .*", "hello xmake"}})
+end
+```
+
+:::tip Detailed API
+For complete parameters and usage of `add_tests`, please refer to: [add_tests API documentation](/api/description/project-target#add-tests)
+:::
+
+### Run all tests
+
+Simply execute `xmake test` to run all configured test cases:
+
+```sh
+$ xmake test
+running tests ...
+[  2%]: test_1/args        .................................... passed 7.000s
+[  5%]: test_1/default     .................................... passed 5.000s
+[  8%]: test_1/fail_output .................................... passed 5.000s
+[ 11%]: test_1/pass_output .................................... passed 6.000s
+[ 13%]: test_2/args        .................................... passed 7.000s
+[ 16%]: test_2/default     .................................... passed 6.000s
+[ 19%]: test_2/fail_output .................................... passed 6.000s
+[ 22%]: test_2/pass_output .................................... passed 6.000s
+[ 25%]: test_3/args        .................................... passed 7.000s
+[ 27%]: test_3/default     .................................... passed 7.000s
+[ 30%]: test_3/fail_output .................................... passed 6.000s
+[ 33%]: test_3/pass_output .................................... passed 6.000s
+[ 36%]: test_4/args        .................................... passed 6.000s
+[ 38%]: test_4/default     .................................... passed 6.000s
+[ 41%]: test_4/fail_output .................................... passed 5.000s
+[ 44%]: test_4/pass_output .................................... passed 6.000s
+[ 47%]: test_5/args        .................................... passed 5.000s
+[ 50%]: test_5/default     .................................... passed 6.000s
+[ 52%]: test_5/fail_output .................................... failed 6.000s
+[ 55%]: test_5/pass_output .................................... failed 5.000s
+[ 58%]: test_6/args        .................................... passed 7.000s
+[ 61%]: test_6/default     .................................... passed 6.000s
+[ 63%]: test_6/fail_output .................................... passed 6.000s
+[ 66%]: test_6/pass_output .................................... passed 6.000s
+[ 69%]: test_7/args        .................................... failed 6.000s
+[ 72%]: test_7/default     .................................... failed 7.000s
+[ 75%]: test_7/fail_output .................................... failed 6.000s
+[ 77%]: test_7/pass_output .................................... failed 5.000s
+[ 80%]: test_8/args        .................................... passed 7.000s
+[ 83%]: test_8/default     .................................... passed 6.000s
+[ 86%]: test_8/fail_output .................................... passed 6.000s
+[ 88%]: test_8/pass_output .................................... failed 5.000s
+[ 91%]: test_9/args        .................................... passed 6.000s
+[ 94%]: test_9/default     .................................... passed 6.000s
+[ 97%]: test_9/fail_output .................................... passed 6.000s
+[100%]: test_9/pass_output .................................... passed 6.000s
+
+80% tests passed, 7 tests failed out of 36, spent 0.242s
+```
+
+### Run specific test targets
+
+You can specify to run a specific test:
+
+```sh
+$ xmake test targetname/testname
+```
+
+Or run all tests of a target or batch tests by pattern matching:
+
+```sh
+$ xmake test targetname/*
+$ xmake test targetname/foo*
+```
+
+You can also run tests with the same name for all targets:
+
+```sh
+$ xmake test */testname
+```
+
+## Test configuration options
+
+`add_tests` supports the following configuration parameters:
+
+| Parameter | Description |
+|-----------|-------------|
+| `runargs` | Test run argument string or array |
+| `runenvs` | Test run environment variable table |
+| `timeout` | Test timeout in seconds |
+| `trim_output` | Whether to trim output whitespace |
+| `pass_outputs` | Expected output patterns for test to pass |
+| `fail_outputs` | Output patterns that should cause test to fail |
+| `build_should_pass` | Test should build successfully |
+| `build_should_fail` | Test should fail to build |
+| `files` | Additional test files to compile |
+| `defines` | Additional defines for test compilation |
+| `realtime_output` | Show test output in real-time |
+
+### Example configurations
+
+#### Test with arguments
+
+```lua
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    add_tests("with_args", {runargs = {"--verbose", "--mode=test"}})
+```
+
+:::tip Related APIs
+- `set_runargs`: [Set target run arguments](/api/description/project-target#set-runargs)
+- `set_rundir`: [Set run working directory](/api/description/project-target#set-rundir)
+- `add_runenvs`: [Add run environment variables](/api/description/project-target#add-runenvs)
+:::
+
+#### Test with expected output
+
+```lua
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    add_tests("output_test", {pass_outputs = ".*success.*", trim_output = true})
+```
+
+#### Test with timeout
+
+```lua
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    add_tests("timeout_test", {timeout = 5}) -- 5 seconds timeout
+```
+
+#### Test with environment variables
+
+```lua
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    add_tests("env_test", {runenvs = {TEST_MODE = "1", DEBUG = "true"}})
+```
+
+:::tip Related APIs
+- `add_runenvs`: [Add run environment variables](/api/description/project-target#add-runenvs)
+- `set_runenv`: [Set run environment variable](/api/description/project-target#set-runenv)
+:::
+
+#### Test build failure
+
+```lua
+target("compile_fail_test")
+    set_kind("binary")
+    add_files("src/invalid.cpp")
+    add_tests("should_fail", {build_should_fail = true})
+```
+
+:::tip Related APIs
+- `set_default`: [Set target default build](/api/description/project-target#set-default)
+- `set_kind`: [Set target type](/api/description/project-target#set-kind)
+:::
+
+#### Add extra code files
+
+`add_tests` supports adding extra code files for compilation through the `files` parameter, which is very useful for unit testing:
+
+```lua
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    add_tests("test_with_stub", {
+        files = "tests/stub_*.cpp",  -- Add extra test files
+        defines = "TEST_MODE",
+        remove_files = "src/main.cpp"  -- Remove unwanted files
+    })
+```
+
+:::tip Use cases
+- **Unit testing**: Add test code files without modifying original source code
+- **Stub code**: Provide mock implementations for testing
+- **Conditional compilation**: Add test-specific macro definitions via `defines`
+- **File replacement**: Remove unwanted files using `remove_files` (e.g., main.cpp)
+:::
+
+Taking doctest as an example, you can externally unit test without modifying any main.cpp:
+
+```lua
+target("doctest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    for _, testfile in ipairs(os.files("tests/*.cpp")) do
+        add_tests(path.basename(testfile), {
+            files = testfile,
+            remove_files = "src/main.cpp",
+            languages = "c++11",
+            defines = "DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN"
+        })
+    end
+end
+```
+
+## Integrating Third-party Testing Frameworks
+
+`xmake test` can integrate well with third-party testing frameworks like doctest, gtest, etc., to achieve more powerful testing capabilities.
+
+### doctest Integration Example
+
+```lua
+add_rules("mode.debug", "mode.release")
+add_requires("doctest")
+
+target("doctest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    for _, testfile in ipairs(os.files("tests/*.cpp")) do
+        add_tests(path.basename(testfile), {
+            files = testfile,
+            remove_files = "src/main.cpp",
+            languages = "c++11",
+            packages = "doctest",  -- Integrate doctest package
+            defines = "DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN"
+        })
+    end
+```
+
+Test file example (`tests/test_1.cpp`):
+
+```cpp
+#include "doctest/doctest.h"
+
+static int factorial(int number) {
+    return number <= 1 ? number : factorial(number - 1) * number;
+}
+
+TEST_CASE("testing the factorial function") {
+    CHECK(factorial(1) == 1);
+    CHECK(factorial(2) == 2);
+    CHECK(factorial(3) == 6);
+    CHECK(factorial(10) == 3628800);
+}
+```
+
+### gtest Integration Example
+
+```lua
+add_rules("mode.debug", "mode.release")
+add_requires("gtest")
+
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    for _, testfile in ipairs(os.files("tests/*.cpp")) do
+        add_tests(path.basename(testfile), {
+            files = testfile,
+            remove_files = "src/main.cpp",
+            packages = "gtest",  -- Integrate gtest package
+            defines = "TEST_MAIN"
+        })
+    end
+```
+
+:::tip Framework Advantages
+- **doctest**: Lightweight, header-only, easy to integrate
+- **gtest**: Feature-rich, maintained by Google, active community
+- **Catch2**: Modern C++ style, powerful features
+:::
+
+### Dynamic Library Testing
+
+You can also test dynamic libraries:
+
+```lua
+target("mylib")
+    set_kind("shared")
+    add_files("src/*.cpp")
+
+target("mylib_test")
+    set_kind("binary")
+    add_deps("mylib")
+    add_files("tests/*.cpp")
+    add_packages("gtest")
+    add_tests("default")
+
+## Verbose output
+
+Use `-v` to get verbose output:
+
+```sh
+$ xmake test -v
+```
+
+Use `-vD` to view detailed test failure error messages:
+
+```sh
+$ xmake test -vD
+```
+
+The `-vD` parameter displays more detailed log output, including output file paths and error information for each test:
+
+```sh
+report of tests:
+[  2%]: test_10/compile_fail .... passed 0.001s
+[  4%]: test_11/compile_pass .... failed 0.001s
+errors: build/.gens/test_11/macosx/x86_64/release/tests/test_11/compile_pass.errors.log
+[  7%]: test_1/args ............. passed 0.045s
+stdout: build/.gens/test_1/macosx/x86_64/release/tests/test_1/args.stdout.log
+[  9%]: test_1/default .......... passed 0.046s
+stdout: build/.gens/test_1/macosx/x86_64/release/tests/test_1/default.stdout.log
+[ 11%]: test_1/fail_output ...... passed 0.046s
+stdout: build/.gens/test_1/macosx/x86_64/release/tests/test_1/fail_output.stdout.log
+[ 14%]: test_1/pass_output ...... passed 0.047s
+stdout: build/.gens/test_1/macosx/x86_64/release/tests/test_1/pass_output.stdout.log
+...
+[100%]: test_timeout/run_timeout  failed 1.007s
+errors: build/.gens/test_timeout/macosx/x86_64/release/tests/test_timeout/run_timeout.errors.log
+
+Detailed summary:
+Failed tests:
+ - test_11/compile_pass
+ - test_5/fail_output
+ - test_5/pass_output
+ - test_7/args
+ - test_7/default
+ - test_7/fail_output
+ - test_7/pass_output
+ - test_8/pass_output
+ - test_timeout/run_timeout
+
+78% tests passed, 9 test(s) failed out of 42, spent 1.212s
+```
+
+### Log file description
+
+When using `-vD`, xmake generates the following log files:
+
+- **stdout logs**: `build/.gens/{target}/tests/{testname}.stdout.log` - Standard output of tests
+- **errors logs**: `build/.gens/{target}/tests/{testname}.errors.log` - Error output of tests
+- **build error logs**: Detailed error information when compilation fails
+
+These log files are very useful for debugging test failure issues, allowing you to view specific output content and error information.
+
+## Group testing
+
+You can group tests using pattern matching:
+
+```sh
+# Run all tests starting with "unit_"
+$ xmake test */unit_*
+
+# Run all tests for targets starting with "test_"
+$ xmake test test_*/*
+
+# Run specific test across all targets
+$ xmake test */default
+```
+
+## Continuous integration
+
+For CI/CD environments, you can use the following patterns:
+
+```sh
+# Run tests and exit with error code on failure
+$ xmake test
+
+# Run tests with detailed output for CI logs
+$ xmake test -v
+
+# Run specific test groups
+$ xmake test unit_tests/*
+$ xmake test integration_tests/*
+```
+
+The test command will return a non-zero exit code if any tests fail, making it suitable for CI pipelines.

+ 1 - 0
docs/zh/config.ts

@@ -234,6 +234,7 @@ function guideSidebar(): DefaultTheme.SidebarItem[] {
         { text: '编译配置', link: 'basic-commands/build-configuration' },
         { text: '构建目标', link: 'basic-commands/build-targets' },
         { text: '运行目标', link: 'basic-commands/run-targets' },
+        { text: '运行测试', link: 'basic-commands/run-tests' },
         { text: '安装卸载', link: 'basic-commands/install-and-uninstall' },
         { text: '打包程序', link: 'basic-commands/pack-programs' },
         { text: '交叉编译', link: 'basic-commands/cross-compilation' },

+ 398 - 0
docs/zh/guide/basic-commands/run-tests.md

@@ -0,0 +1,398 @@
+# 运行测试 {#run-tests}
+
+Xmake 提供了内置的 `xmake test` 命令用于运行单元测试和测试用例。从 v2.8.5 版本开始,你可以通过 `add_tests` 在需要测试的目标上配置测试用例,然后自动执行所有测试。
+
+这为自动化测试提供了极大的便利,即使目标被设置为 `set_default(false)`,xmake 在执行测试时仍会自动编译它,然后运行所有测试。
+
+## 命令格式
+
+```sh
+$ xmake test [options] [target/testname]
+```
+
+## 基本用法
+
+### 配置测试用例
+
+首先,我们需要使用 `add_tests` 为目标配置测试用例:
+
+```lua
+add_rules("mode.debug", "mode.release")
+
+for _, file in ipairs(os.files("src/test_*.cpp")) do
+    local name = path.basename(file)
+    target(name)
+        set_kind("binary")
+        set_default(false)
+        add_files("src/" .. name .. ".cpp")
+        add_tests("default")
+        add_tests("args", {runargs = {"foo", "bar"}})
+        add_tests("pass_output", {trim_output = true, runargs = "foo", pass_outputs = "hello foo"})
+        add_tests("fail_output", {fail_outputs = {"hello2 .*", "hello xmake"}})
+end
+```
+
+:::tip 详细 API
+关于 `add_tests` 的完整参数和使用说明,请参考:[add_tests 接口文档](/zh/api/description/project-target#add-tests)
+:::
+
+### 运行所有测试
+
+只需执行 `xmake test` 即可运行所有配置的测试用例:
+
+```sh
+$ xmake test
+running tests ...
+[  2%]: test_1/args        .................................... passed 7.000s
+[  5%]: test_1/default     .................................... passed 5.000s
+[  8%]: test_1/fail_output .................................... passed 5.000s
+[ 11%]: test_1/pass_output .................................... passed 6.000s
+[ 13%]: test_2/args        .................................... passed 7.000s
+[ 16%]: test_2/default     .................................... passed 6.000s
+[ 19%]: test_2/fail_output .................................... passed 6.000s
+[ 22%]: test_2/pass_output .................................... passed 6.000s
+[ 25%]: test_3/args        .................................... passed 7.000s
+[ 27%]: test_3/default     .................................... passed 7.000s
+[ 30%]: test_3/fail_output .................................... passed 6.000s
+[ 33%]: test_3/pass_output .................................... passed 6.000s
+[ 36%]: test_4/args        .................................... passed 6.000s
+[ 38%]: test_4/default     .................................... passed 6.000s
+[ 41%]: test_4/fail_output .................................... passed 5.000s
+[ 44%]: test_4/pass_output .................................... passed 6.000s
+[ 47%]: test_5/args        .................................... passed 5.000s
+[ 50%]: test_5/default     .................................... passed 6.000s
+[ 52%]: test_5/fail_output .................................... failed 6.000s
+[ 55%]: test_5/pass_output .................................... failed 5.000s
+[ 58%]: test_6/args        .................................... passed 7.000s
+[ 61%]: test_6/default     .................................... passed 6.000s
+[ 63%]: test_6/fail_output .................................... passed 6.000s
+[ 66%]: test_6/pass_output .................................... passed 6.000s
+[ 69%]: test_7/args        .................................... failed 6.000s
+[ 72%]: test_7/default     .................................... failed 7.000s
+[ 75%]: test_7/fail_output .................................... failed 6.000s
+[ 77%]: test_7/pass_output .................................... failed 5.000s
+[ 80%]: test_8/args        .................................... passed 7.000s
+[ 83%]: test_8/default     .................................... passed 6.000s
+[ 86%]: test_8/fail_output .................................... passed 6.000s
+[ 88%]: test_8/pass_output .................................... failed 5.000s
+[ 91%]: test_9/args        .................................... passed 6.000s
+[ 94%]: test_9/default     .................................... passed 6.000s
+[ 97%]: test_9/fail_output .................................... passed 6.000s
+[100%]: test_9/pass_output .................................... passed 6.000s
+
+80% tests passed, 7 tests failed out of 36, spent 0.242s
+```
+
+### 运行指定的测试目标
+
+你可以指定运行特定的测试:
+
+```sh
+$ xmake test targetname/testname
+```
+
+或者通过模式匹配运行一个目标的所有测试或批量测试:
+
+```sh
+$ xmake test targetname/*
+$ xmake test targetname/foo*
+```
+
+你也可以运行所有目标中同名的测试:
+
+```sh
+$ xmake test */testname
+```
+
+## 测试配置选项
+
+`add_tests` 支持以下配置参数:
+
+| 参数 | 描述 |
+|------|------|
+| `runargs` | 测试运行参数字符串或数组 |
+| `runenvs` | 测试运行环境变量表 |
+| `timeout` | 测试超时时间(秒) |
+| `trim_output` | 是否修剪输出空白字符 |
+| `pass_outputs` | 测试通过的预期输出模式 |
+| `fail_outputs` | 应导致测试失败的输出模式 |
+| `build_should_pass` | 测试应该构建成功 |
+| `build_should_fail` | 测试应该构建失败 |
+| `files` | 额外的测试文件编译 |
+| `defines` | 测试编译的额外定义 |
+| `realtime_output` | 实时显示测试输出 |
+
+### 配置示例
+
+#### 带参数的测试
+
+```lua
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    add_tests("with_args", {runargs = {"--verbose", "--mode=test"}})
+```
+
+:::tip 相关 API
+- `set_runargs`: [设置目标运行参数](/zh/api/description/project-target#set-runargs)
+- `set_rundir`: [设置运行工作目录](/zh/api/description/project-target#set-rundir)
+- `add_runenvs`: [添加运行环境变量](/zh/api/description/project-target#add-runenvs)
+:::
+
+#### 带预期输出的测试
+
+```lua
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    add_tests("output_test", {pass_outputs = ".*success.*", trim_output = true})
+```
+
+#### 带超时的测试
+
+```lua
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    add_tests("timeout_test", {timeout = 5}) -- 5秒超时
+```
+
+#### 带环境变量的测试
+
+```lua
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    add_tests("env_test", {runenvs = {TEST_MODE = "1", DEBUG = "true"}})
+```
+
+:::tip 相关 API
+- `add_runenvs`: [添加运行环境变量](/zh/api/description/project-target#add-runenvs)
+- `set_runenv`: [设置运行环境变量](/zh/api/description/project-target#set-runenv)
+:::
+
+#### 构建失败测试
+
+```lua
+target("compile_fail_test")
+    set_kind("binary")
+    add_files("src/invalid.cpp")
+    add_tests("should_fail", {build_should_fail = true})
+```
+
+:::tip 相关 API
+- `set_default`: [设置目标默认构建](/zh/api/description/project-target#set-default)
+- `set_kind`: [设置目标类型](/zh/api/description/project-target#set-kind)
+:::
+
+#### 添加额外代码文件
+
+`add_tests` 支持通过 `files` 参数添加额外的代码文件进行编译,这对于单元测试非常有用:
+
+```lua
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    add_tests("test_with_stub", {
+        files = "tests/stub_*.cpp",  -- 添加额外的测试文件
+        defines = "TEST_MODE",
+        remove_files = "src/main.cpp"  -- 移除不需要的文件
+    })
+```
+
+:::tip 使用场景
+- **单元测试**:添加测试代码文件而不修改原始源码
+- **桩代码**:为测试提供模拟的实现
+- **条件编译**:通过 `defines` 添加测试特定的宏定义
+- **文件替换**:使用 `remove_files` 移除不需要的文件(如 main.cpp)
+:::
+
+以 doctest 为例,可以在不修改任何 main.cpp 的情况下外置单元测试:
+
+```lua
+target("doctest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    for _, testfile in ipairs(os.files("tests/*.cpp")) do
+        add_tests(path.basename(testfile), {
+            files = testfile,
+            remove_files = "src/main.cpp",
+            languages = "c++11",
+            defines = "DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN"
+        })
+    end
+end
+```
+
+## 集成第三方测试框架
+
+`xmake test` 可以很好地集成 doctest、gtest 等第三方测试框架,实现更强大的测试功能。
+
+### doctest 集成示例
+
+```lua
+add_rules("mode.debug", "mode.release")
+add_requires("doctest")
+
+target("doctest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    for _, testfile in ipairs(os.files("tests/*.cpp")) do
+        add_tests(path.basename(testfile), {
+            files = testfile,
+            remove_files = "src/main.cpp",
+            languages = "c++11",
+            packages = "doctest",  -- 集成 doctest 包
+            defines = "DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN"
+        })
+    end
+```
+
+测试文件示例 (`tests/test_1.cpp`):
+
+```cpp
+#include "doctest/doctest.h"
+
+static int factorial(int number) {
+    return number <= 1 ? number : factorial(number - 1) * number;
+}
+
+TEST_CASE("testing the factorial function") {
+    CHECK(factorial(1) == 1);
+    CHECK(factorial(2) == 2);
+    CHECK(factorial(3) == 6);
+    CHECK(factorial(10) == 3628800);
+}
+```
+
+### gtest 集成示例
+
+```lua
+add_rules("mode.debug", "mode.release")
+add_requires("gtest")
+
+target("mytest")
+    set_kind("binary")
+    add_files("src/*.cpp")
+    for _, testfile in ipairs(os.files("tests/*.cpp")) do
+        add_tests(path.basename(testfile), {
+            files = testfile,
+            remove_files = "src/main.cpp",
+            packages = "gtest",  -- 集成 gtest 包
+            defines = "TEST_MAIN"
+        })
+    end
+```
+
+:::tip 框架优势
+- **doctest**:轻量级,仅头文件,易于集成
+- **gtest**:功能丰富,Google 维护,社区活跃
+- **Catch2**:现代 C++ 风格,功能强大
+:::
+
+### 动态库测试
+
+也可以对动态库进行测试:
+
+```lua
+target("mylib")
+    set_kind("shared")
+    add_files("src/*.cpp")
+
+target("mylib_test")
+    set_kind("binary")
+    add_deps("mylib")
+    add_files("tests/*.cpp")
+    add_packages("gtest")
+    add_tests("default")
+
+## 详细输出
+
+使用 `-v` 获取详细输出:
+
+```sh
+$ xmake test -v
+```
+
+使用 `-vD` 查看详细的测试失败错误信息:
+
+```sh
+$ xmake test -vD
+```
+
+`-vD` 参数会显示更详细的日志输出,包括每个测试的输出文件路径和错误信息:
+
+```sh
+report of tests:
+[  2%]: test_10/compile_fail .... passed 0.001s
+[  4%]: test_11/compile_pass .... failed 0.001s
+errors: build/.gens/test_11/macosx/x86_64/release/tests/test_11/compile_pass.errors.log
+[  7%]: test_1/args ............. passed 0.045s
+stdout: build/.gens/test_1/macosx/x86_64/release/tests/test_1/args.stdout.log
+[  9%]: test_1/default .......... passed 0.046s
+stdout: build/.gens/test_1/macosx/x86_64/release/tests/test_1/default.stdout.log
+[ 11%]: test_1/fail_output ...... passed 0.046s
+stdout: build/.gens/test_1/macosx/x86_64/release/tests/test_1/fail_output.stdout.log
+[ 14%]: test_1/pass_output ...... passed 0.047s
+stdout: build/.gens/test_1/macosx/x86_64/release/tests/test_1/pass_output.stdout.log
+...
+[100%]: test_timeout/run_timeout  failed 1.007s
+errors: build/.gens/test_timeout/macosx/x86_64/release/tests/test_timeout/run_timeout.errors.log
+
+Detailed summary:
+Failed tests:
+ - test_11/compile_pass
+ - test_5/fail_output
+ - test_5/pass_output
+ - test_7/args
+ - test_7/default
+ - test_7/fail_output
+ - test_7/pass_output
+ - test_8/pass_output
+ - test_timeout/run_timeout
+
+78% tests passed, 9 test(s) failed out of 42, spent 1.212s
+```
+
+### 日志文件说明
+
+使用 `-vD` 时,xmake 会生成以下日志文件:
+
+- **stdout 日志**:`build/.gens/{target}/tests/{testname}.stdout.log` - 测试的标准输出
+- **errors 日志**:`build/.gens/{target}/tests/{testname}.errors.log` - 测试的错误输出
+- **构建错误日志**:编译失败时的详细错误信息
+
+这些日志文件对于调试测试失败问题非常有用,可以查看具体的输出内容和错误信息。
+
+## 分组测试
+
+你可以使用模式匹配对测试进行分组:
+
+```sh
+# 运行所有以 "unit_" 开头的测试
+$ xmake test */unit_*
+
+# 运行所有以 "test_" 开头的目标的测试
+$ xmake test test_*/*
+
+# 运行所有目标中的特定测试
+$ xmake test */default
+```
+
+## 持续集成
+
+对于 CI/CD 环境,可以使用以下模式:
+
+```sh
+# 运行测试,失败时返回错误码
+$ xmake test
+
+# 运行测试并提供详细输出用于 CI 日志
+$ xmake test -v
+
+# 运行特定测试组
+$ xmake test unit_tests/*
+$ xmake test integration_tests/*
+```
+
+测试命令在任何测试失败时都会返回非零退出码,这使其适合用于 CI 流水线。