> For the complete documentation index, see [llms.txt](https://chenxiaowei.gitbook.io/cmake-cookbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://chenxiaowei.gitbook.io/cmake-cookbook/15.0-chinese/15.5-chinese.md).

# 15.5 移植测试

现在，来讨论如何将测试从引用构建移植到CMake。

## 准备工作

如果移植的项目包含测试目标，或任何形式的自动化测试，以及测试脚本。第一步，运行传统的测试步骤，并记录所使用的命令。对于Vim项目，可以从`src/testdir/Makefile`开始。在`src/testdir/Makefile`和测试脚本中的一些对于测试的定义，我们将在`src/testdir/CMakeLists.txt`中进行相应的定义。所以，我们必须在`src/CMakeLists.txt`中引用它:

```
add_subdirectory(testdir)
```

处理`src/CMakeLists.txt`之前，我们还应该在主`CMakeLists.txt`中启用测试:

```
# enable the test target
enable_testing()

# process src/CMakeLists.txt in its own scope
add_subdirectory(src)
```

目前为止，使用`add_test`填充`src/testdir/CMakeLists.txt`之前，测试目标为空。在`add_test`中指定要运行的测试名称和命令。该命令可以用任何语言编写。CMake的关键部分是，如果测试成功，脚本返回零；如果测试失败，脚本返回非零。对于Vim，我们需要多步骤测试，这将在下一节中讨论。

## 实现多步测试

在`src/testdir/Makefile`的目标表明，Vim代码运行测试多步测试：

1. Vim脚本可执行测试流程，产生一个输出文件
2. 输出文件是与参考文件进行比，,如果这些文件相同，测试成功
3. 删除临时文件

由于`add_test`只能执行一个命令，因此无法以可移植的方式将其放到单个`add_test`中。一种解决方案是在Python脚本中定义测试步骤，并使用一些参数执行Python脚本。这里提供的另一种选择，也是跨平台的，在单独的CMake脚本中定义测试步骤，并使用`add_test`执行这个脚本。我们将在`src/testdir/test.cmake`中定义测试步骤:

```
function(execute_test _vim_executable _working_dir _test_script)
  # generates test.out
  execute_process(
    COMMAND ${_vim_executable} -f -u unix.vim -U NONE --noplugin --not-a-term -s dotest.in ${_test_script}.in
    WORKING_DIRECTORY ${_working_dir}
    )

  # compares test*.ok and test.out
  execute_process(
    COMMAND ${CMAKE_COMMAND} -E compare_files ${_test_script}.ok test.out
    WORKING_DIRECTORY ${_working_dir}
    RESULT_VARIABLE files_differ
    OUTPUT_QUIET
    ERROR_QUIET
    )

  # removes leftovers
  file(REMOVE ${_working_dir}/Xdotest)

  # we let the test fail if the files differ
  if(files_differ)
      message(SEND_ERROR "test ${_test_script} failed")
  endif()
endfunction()

execute_test(${VIM_EXECUTABLE} ${WORKING_DIR} ${TEST_SCRIPT})
```

同样，我们选择函数而不是宏，为的是使得变量不会超出函数作用域。它将调用`execute_test`函数，处理这个脚本。但是，我们必须确保`${VIM_EXECUTABLE}`、`${WORKING_DIR}`和`${TEST_SCRIPT}`是在外部定义。`src/testdir/CMakeLists.txt`中定义:

```
add_test(
  NAME
      test1
  COMMAND
    ${CMAKE_COMMAND} -D VIM_EXECUTABLE=$<TARGET_FILE:vim>
    -D WORKING_DIR=${CMAKE_CURRENT_LIST_DIR}
    -D TEST_SCRIPT=test1
    -P ${CMAKE_CURRENT_LIST_DIR}/test.cmake
  WORKING_DIRECTORY
      ${PROJECT_BINARY_DIR}
  )
```

Vim项目有很多测试，但是在这个例子中，我们只移植了一个(test1)。

## 测试建议

对于移植测试，我们可以给出至少两个建议。

1. 要确保测试并不总是报告成功，如果破坏了代码或修改了验证数据，请验证测试是否失败。
2. 添加测试的成本估算，以便在并行运行时，首先启动较长的测试，以最小化总测试时间。
