【问题标题】:CMake: Project structure with unit testsCMake:带有单元测试的项目结构
【发布时间】:2013-01-04 23:18:52
【问题描述】:

我正在尝试构建我的项目以包含生产源(在src 子文件夹中)和测试(在test 子文件夹中)。我正在使用 CMake 来构建它。作为一个最小的例子,我有以下文件:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8) 
project (TEST) 

add_subdirectory (src) 
add_subdirectory (test) 

src/CMakeLists.txt:

add_executable (demo main.cpp sqr.cpp) 

src/sqr.h

#ifndef SQR_H
#define SQR_H
double sqr(double);    
#endif // SQR_H

src/sqr.cpp

#include "sqr.h"
double sqr(double x) { return x*x; }

src/main.cpp - 使用 sqr,没关系

测试/CMakeLists.txt:

find_package(Boost COMPONENTS system filesystem unit_test_framework REQUIRED)

include_directories (${TEST_SOURCE_DIR}/src) 

ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) 

add_executable (test test.cpp ${TEST_SOURCE_DIR}/src/sqr.cpp) 

target_link_libraries(test
                      ${Boost_FILESYSTEM_LIBRARY}
                      ${Boost_SYSTEM_LIBRARY}
                      ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                      )

enable_testing()
add_test(MyTest test)

测试/test.cpp:

#define BOOST_TEST_MODULE SqrTests
#include <boost/test/unit_test.hpp>

#include "sqr.h"

BOOST_AUTO_TEST_CASE(FailTest)
{
    BOOST_CHECK_EQUAL(5, sqr(2));
}

BOOST_AUTO_TEST_CASE(PassTest)
{
    BOOST_CHECK_EQUAL(4, sqr(2));
}

几个问题:

  1. 这种结构有意义吗?构建此代码时的最佳实践是什么? (我来自 C# 和 java,从某种意义上说它更容易)
  2. 我不喜欢我必须在test/CMakeLists.txt 文件中列出src 文件夹中的所有文件。如果这是一个图书馆项目,我只会链接图书馆。有没有办法避免列出其他项目中的所有 cpp 文件?
  3. enable_testing()add_test(MyTest test) 行在做什么?我没有看到任何效果。如何从 CMake(或 CTest)运行测试?
  4. 到目前为止,我只是在根文件夹中运行了cmake .,但这会造成到处都是临时文件的混乱。如何才能得到结构合理的编译结果?

【问题讨论】:

  • 我认为自己是 CMake 新手,所以我不知道公认的最佳实践是什么,但 FWIW 我会创建一个主要和测试都依赖的“sqr”库*。 (* 或其道德等价物)

标签: c++ unit-testing boost cmake boost-test


【解决方案1】:

对于问题 1 和 2,我建议从您的非测试文件中创建一个库,不包括 main.cpp(在这种情况下只是 src/sqr.cpp 和 src/sqr.h),然后您可以避免列出 (更重要的是重新编译)所有源代码。

对于问题 3,这些命令会添加一个名为“MyTest”的测试,它会调用您的可执行文件“test”而无需任何参数。但是,由于您已将这些命令添加到 test/CMakeLists.txt 而不是顶级 CMakeLists.txt,因此您只能从构建树的“test”子目录中调用测试(尝试cd test &amp;&amp; ctest -N)。如果您希望测试可以从您的顶级构建目录运行,您需要从顶级 CMakeLists.txt 调用 add_test。这也意味着您必须使用更详细的 add_test 形式,因为您的测试 exe 没有在同一个 CMakeLists.txt 中定义

在您的情况下,由于您在根文件夹中运行 cmake,因此您的构建树和源代码树是一回事。这被称为源内构建,并不理想,这就引出了问题 4。

生成构建树的首选方法是进行源代码外构建,即在源代码树之外的某处创建一个目录并从那里执行 cmake。即使在项目的根目录中创建一个“构建”目录并执行cmake ..,也会提供一个不会干扰源代码树的干净结构。

最后一点是避免调用可执行文件“test”(区分大小写)。原因见this answer

要实现这些更改,我会执行以下操作:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src) 
add_subdirectory (test)
enable_testing ()
add_test (NAME MyTest COMMAND Test)


src/CMakeLists.txt:

add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)


测试/CMakeLists.txt:

find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
                     ${Boost_INCLUDE_DIRS}
                     )
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
                       Sqr
                       ${Boost_FILESYSTEM_LIBRARY}
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                       )

【讨论】:

  • 我刚刚注意到您还相应地将 .h 文件添加到了 CMakeLists.txt 文件中。是必需的吗?如果我把它们排除在外,会发生什么?
  • @Grzenio 这只是一个方便的功能——它们像 MSVC 一样出现在 IDE 中作为目标的一部分,但除此之外没有任何效果。
  • TEST_SOURCE_DIR 设置在哪里?
  • 调用project (TEST)时由CMake自动设置-见cmake.org/cmake/help/v3.6/variable/PROJECT-NAME_SOURCE_DIR.html
  • 如果我在测试文件夹中有很多测试用例,如何在不调用很多add_test manully 的情况下有效地添加它们?
【解决方案2】:

我喜欢@Fraser 的示例,但会在 test/CMakeLists.txt 中使用 add_test 命令,并在 add_subdirectory(test) 之前使用 enable_testing。

这样您就可以从顶级构建目录运行您的测试,同时在 test/CMakeLists.txt 中指定您的测试。

结果应该是这样的(我重用了@Fraser 的例子):

CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)

enable_testing ()
add_subdirectory (test)

src/CMakeLists.txt

add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)

测试/CMakeLists.txt

find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
                     ${Boost_INCLUDE_DIRS}
                     )
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
                       Sqr
                       ${Boost_FILESYSTEM_LIBRARY}
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                       )
add_test (NAME MyTest COMMAND Test)

【讨论】:

  • 谢谢,我没有通过 ctest -N 显示任何测试,直到您在添加子目录之前启用测试的提示。
  • @alaferg:否则它们会在构建目录中的测试子目录中结束。
  • 我希望 CMake 有类似结构的东西。
  • @ruipacheco 您可以根据职责将 CMakeLists 拆分为不同的子文件夹。他们每个人都应该保持简短。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 2022-07-28
  • 2018-09-08
  • 2021-04-02
  • 2014-07-03
  • 1970-01-01
相关资源
最近更新 更多