简体   繁体   English

CMake:具有单元测试的项目结构

[英]CMake: Project structure with unit tests

I am trying to structure my project to include the production sources (in src subfolder) and tests (in test subfolder). 我正在尝试构建我的项目以包含生产源(在src子文件夹中)和测试(在test子文件夹中)。 I am using CMake to build this. 我正在使用CMake来构建它。 As a minimal example I have the following files: 作为一个最小的例子,我有以下文件:

CMakeLists.txt: 的CMakeLists.txt:

cmake_minimum_required (VERSION 2.8) 
project (TEST) 

add_subdirectory (src) 
add_subdirectory (test) 

src/CMakeLists.txt: SRC /的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) (我来自C#和java,从某种意义上来说它更容易)
  2. I don't like the fact that I have to list all the files from the src folder in the test/CMakeLists.txt file. 我不喜欢我必须列出test/CMakeLists.txt文件中src文件夹中的所有文件。 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? 有没有办法避免列出其他项目中的所有cpp文件?
  3. What are the lines enable_testing() and add_test(MyTest test) doing? enable_testing()add_test(MyTest test)做什么的? I haven't seen any effect. 我没有看到任何影响。 How can I run the tests from CMake (or CTest)? 我怎样才能从CMake(或CTest)运行测试?
  4. So far I just ran cmake . 到目前为止,我刚刚运行了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? 如何以合理的结构获得编译结果?

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. 对于问题3,这些命令添加了一个名为“MyTest”的测试,它在没有任何参数的情况下调用您的可执行文件“test”。 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 ). 但是,由于您已将这些命令添加到test / CMakeLists.txt而不是顶级CMakeLists.txt,因此您只能从构建树的“test”子目录中调用测试(尝试cd test && ctest -N )。 If you want the test to be runnable from your top-level build directory, you'd need to call add_test from the top-level CMakeLists.txt. 如果您希望测试可以从顶级构建目录运行,则需要从顶级CMakeLists.txt调用add_test This also means you have to use the more verbose form of add_test since your test exe isn't defined in the same 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. 在您的情况下,由于您在根文件夹中运行cmake,因此构建树和源树是同一个。 This is known as an in-source build and isn't ideal, which leads to question 4. 这被称为源内构建,并不理想,这导致问题4。

The preferred method for generating the build tree is to do an out-of-source build, ie create a directory somewhere outside of your source tree and execute cmake from there. 生成构建树的首选方法是进行源外构建,即在源树之外的某个位置创建一个目录并从那里执行cmake。 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 ..也会提供一个干净的结构,不会干扰源树。

One final point is to avoid calling executables "test" (case-sensitive). 最后一点是避免调用可执行文件“test”(区分大小写)。 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: SRC /的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}
                       )

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 SRC /的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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM