C++ CMake:带有单元测试的项目结构

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14446495/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:20:42  来源:igfitidea点击:

CMake: Project structure with unit tests

c++unit-testingboostcmakeboost-test

提问by Grzenio

I am trying to structure my project to include the production sources (in srcsubfolder) and tests (in testsubfolder). I am using CMake to build this. As a minimal example I have the following files:

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

CMakeLists.txt:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8) 
project (TEST) 

add_subdirectory (src) 
add_subdirectory (test) 

src/CMakeLists.txt:

源代码/CMakeLists.txt:

add_executable (demo main.cpp sqr.cpp) 

src/sqr.h

src/sqr.h

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

src/sqr.cpp

src/sqr.cpp

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

src/main.cpp - uses sqr, doesn't really matter

src/main.cpp - 使用 sqr,并不重要

test/CMakeLists.txt:

测试/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/test.cpp:

测试/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));
}

A few questions:

几个问题:

  1. Does this structure make sense? What are the best practises when structuring this code? (I am coming from C# and java, and there it is easier in a sense)
  2. I don't like the fact that I have to list all the files from the srcfolder in the test/CMakeLists.txtfile. If this was a library project, I would just link the library. Is there a way to avoid listing all the cpp files from the other project?
  3. What are the lines enable_testing()and add_test(MyTest test)doing? I haven't seen any effect. How can I run the tests from CMake (or CTest)?
  4. So far I just ran cmake .in the root folder, but this created a mess with temporary files everywhere. How can I get the compilation results in a reasonable structure?
  1. 这种结构有意义吗?构建此代码时的最佳实践是什么?(我来自 C# 和 java,在某种意义上它更容易)
  2. 我不喜欢我必须列出src文件中test/CMakeLists.txt文件夹中的所有文件的事实。如果这是一个图书馆项目,我只会链接图书馆。有没有办法避免列出其他项目中的所有 cpp 文件?
  3. 哪些线路enable_testing()add_test(MyTest test)在干什么?我没有看到任何效果。如何从 CMake(或 CTest)运行测试?
  4. 到目前为止,我只是cmake .在根文件夹中运行,但这造成了到处都是临时文件的混乱。如何以合理的结构获得编译结果?

采纳答案by Fraser

For questions 1 & 2, I would recommend making a library from your non-test files excluding main.cpp (in this case just src/sqr.cpp and src/sqr.h), and then you can avoid listing (and more importantly re-compiling) all the sources twice.

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

For question 3, these commands add a test called "MyTest" which invokes your executable "test" without any arguments. However, since you've added these commands to test/CMakeLists.txt and not your top-level CMakeLists.txt, you can only invoke the test from within the "test" subdirectory of your build tree (try cd test && ctest -N). If you want the test to be runnable from your top-level build directory, you'd need to call add_testfrom the top-level CMakeLists.txt. This also means you have to use the more verbose form of add_testsince your test exe isn't defined in the same CMakeLists.txt

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

In your case, since you're running cmake in the root folder, your build tree and your source tree are one and the same. This is known as an in-source build and isn't ideal, which leads to question 4.

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

The preferred method for generating the build tree is to do an out-of-source build, i.e. create a directory somewhere outside of your source tree and execute cmake from there. Even creating a "build" directory in the root of your project and executing cmake ..would provide a clean structure which won't interfere with your source tree.

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

One final point is to avoid calling executables "test" (case-sensitive). For reasons why, see this answer.

最后一点是避免调用可执行文件“测试”(区分大小写)。有关原因,请参阅此答案

To achieve these changes, I'd do the following:

为了实现这些更改,我将执行以下操作:

CMakeLists.txt:

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:


源代码/CMakeLists.txt:

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


test/CMakeLists.txt:


测试/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}
                       )

回答by Mathias

I like the example of @Fraser but would use the add_test command in the test/CMakeLists.txt and use enable_testing before add_subdirectory(test).

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

This way you can run your tests from the top-level build directory while specifying your tests in the test/CMakeLists.txt.

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

The result would look like this (I reused the example of @Fraser):

结果看起来像这样(我重用了@Fraser 的例子):

CMakeLists.txt

CMakeLists.txt

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

enable_testing ()
add_subdirectory (test)

src/CMakeLists.txt

源代码/CMakeLists.txt

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

test/CMakeLists.txt

测试/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)