在使用CMake构建Windows DLL期间运行单元测试

时间:2013-09-13 21:25:08

标签: c++ unit-testing dll cmake

我有一个用cmake构建的C ++库。该库通过单元测试进行测试,我希望将其作为构建的一部分运行。我希望在库或单元测试源发生变化时运行测试。

我在cmake邮件列表的过去帖子中找到了一些帮助:

http://www.cmake.org/pipermail/cmake/2010-January/034419.html

这种方法在单元测试程序中使用add_custom_command(),在共享或静态库时在Linux上运行,在libary静态时在Windows上运行。问题是构建在Windows上共享的库。在这种情况下,测试在初始构建中运行,但在库更改时不会运行。

以下是一个说明问题的示例:

的CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(xyz)

SET(BUILD_SHARED_LIBS ON)

#----------- build library
if(${BUILD_SHARED_LIBS})
    add_definitions(-DXYZ_SHARED)
endif(${BUILD_SHARED_LIBS})
add_library(${PROJECT_NAME} xyz.cpp xyz.h)

#----------- build unit tests program
add_executable(${PROJECT_NAME}_unit_tests unit_tests.cpp)
target_link_libraries(${PROJECT_NAME}_unit_tests ${PROJECT_NAME})

#----------- run unit tests program after it is built
add_custom_command(TARGET ${PROJECT_NAME}_unit_tests
    POST_BUILD COMMAND ${PROJECT_NAME}_unit_tests)

xyz.h

#pragma once

#ifdef XYZ_SHARED
#ifdef _WIN32
#ifdef xyz_EXPORTS
#define XYZ_EXPORT __declspec(dllexport)
#else
#define XYZ_EXPORT __declspec(dllimport)
#endif
#else //_WIN32
#define XYZ_EXPORT
#endif //_WIN32
#else //XYZ_SHARED
#define XYZ_EXPORT
#endif //XYZ_SHARED

XYZ_EXPORT bool xyz_return_true();

xyz.cpp

#include "xyz.h"

XYZ_EXPORT bool xyz_return_true()
{
    return true;
}

unit_tests.cpp

#include <iostream>
#include "xyz.h"

int main(int argc, char *argv[])
{
    using namespace std;

    cout << "running unit tests: ";

    if (xyz_return_true()) {
        //no error
        cout << "pass" << endl;
        return 0;
    }

    //error
    cout << "fail" << endl;
    return 1;
}

如果我在Windows上构建,那么更改xyz.cpp的函数以返回false并再次构建,则不会运行测试。在这种情况下,我该怎么做才能运行测试?

我认为测试没有运行,因为在构建时xyz_unit_tests.exe只依赖于导入库(xyz.lib)。如果库接口没有更改,则导入库不会更改。

我正在使用Visual Studio 10和cmake 2.8.11.2。

1 个答案:

答案 0 :(得分:1)

您可以通过删除测试可执行文件作为库的构建后事件来触发测试重建。所以,例如:

if(WIN32 AND BUILD_SHARED_LIBS)
  #----------- trigger rebuild of tests if lib has changed
  get_target_property(TestPath ${PROJECT_NAME}_unit_tests LOCATION)
  add_custom_command(TARGET ${PROJECT_NAME}
      POST_BUILD COMMAND ${CMAKE_COMMAND} -E remove ${TestPath}
      COMMENT "Removing ${TestPath}")
endif()

您必须在COMMAND参数中使用LOCATION目标属性而不是生成器表达式,因为这不会在CMake的依赖关系图中引入循环依赖关系。理想情况下,我们将COMMAND参数设为:

COMMAND ${CMAKE_COMMAND} -E remove $<TARGET_FILE:${PROJECT_NAME}_unit_tests>

但这会导致库依赖于可执行文件,显然target_link_libraries调用会导致exe依赖于lib。

可能有一种更好的方法可以使测试可执行文件变得过时而不是仅删除它;这对我来说似乎有点蛮力。但它应该有用。