【问题标题】:How to run a .dll test suite with CMake and Microsoft Unit Test Framework如何使用 CMake 和 Microsoft 单元测试框架运行 .dll 测试套件
【发布时间】:2022-01-18 17:11:53
【问题描述】:

在一个 CMake 项目中,我根据这篇文章生成了一个 C++/CLI 项目和一个测试共享库

CMake for integrated Microsoft Unit Testing Framework (VS2017)

我正在尝试运行测试,但 Visual StudioVisual Studio Code 都无法发现我的测试。

唯一的区别是我创建了一个 test 子文件夹作为 CMake 子项目,它是各自的 CMakeLists.txt,但配置完全相同。

我做错了什么?

谢谢。

【问题讨论】:

    标签: c++ unit-testing cmake clr cil


    【解决方案1】:

    关联问题分析

    您链接的问题的答案有几个问题:

    • 它使用了一些非常古老的 CMake 技术 (include_directories() + link_directories())。请使用一些更新的 3.x 版本的 CMake 并应用现代 CMake 技术[1][2]
    • 此外,您不应将SHARED/STATIC 关键字传递给add_library(),而应使用BUILD_SHARED_LIBS 变量来控制是构建共享二进制文件还是静态二进制文件。
    • 它不完整。您需要调用add_test() 来为ctest 创建测试,否则ctest 和IDE 都无法知道您的单元测试。还有enable_testing()需要在顶层项目中调用,否则add_test()不起作用。

    最小的工作示例

    CMakeLists.txt:

    cmake_minimum_required(VERSION 3.21)
    project(so70759660)
    list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
    
    if(PROJECT_IS_TOP_LEVEL AND BUILD_TESTING)
      enable_testing()
      add_subdirectory(tests)
    endif()
    

    tests/CMakeLists.txt:

    find_package(MSUnitTestFramework REQUIRED)
    find_program(VSTest_EXECUTABLE NAMES vstest.console.exe REQUIRED)
    
    add_library(mytest)
    target_sources(mytest PRIVATE Mytest.cpp)
    target_link_libraries(mytest PRIVATE MSUnitTestFramework::MSUnitTestFramework)
    add_test(NAME mytest COMMAND "${VSTest_EXECUTABLE}" "$<TARGET_FILE:mytest>")
    

    cmake/FindMSUnitTestFramework.cmake:

    add_library(MSUnitTestFramework::MSUnitTestFramework SHARED IMPORTED)
    set_target_properties(MSUnitTestFramework::MSUnitTestFramework PROPERTIES
      INTERFACE_INCLUDE_DIRECTORIES "$ENV{VCInstallDir}Auxiliary/VS/UnitTest/include"
      IMPORTED_IMPLIB "$ENV{VCInstallDir}Auxiliary/VS/UnitTest/lib/x86/Microsoft.VisualStudio.TestTools.CppUnitTestFramework.lib"
    )
    set(MSUnitTestFramework_FOUND TRUE)
    

    注意事项:

    • 使用IMPORTED 目标并通过target_link_libraries() 链接它是include_directories()/include_libraries() 的现代替代方案。
    • FindMSUnitTestFramework 模块负责定位和创建这个导入的目标。请注意,我提供的示例是相当硬编码的,并且在查找库以及可能考虑不同的 Visual Studio 版本或目标体系结构等方面不是很“聪明”。您可能需要对此进行改进。

    tests/MyTest.cpp:

    #include <CppUnitTest.h>
    using namespace Microsoft::VisualStudio::CppUnitTestFramework;
    
    TEST_CLASS(Class1) {
      public:
        TEST_METHOD(Method1) { Assert::AreEqual(0, 0); }
        TEST_METHOD(Method2) { Assert::AreNotEqual(0, 42); }
    };
    

    CMakePresets.json:

    {
        "version": 3,
        "configurePresets": [
            {
                "name": "vs2022",
                "generator": "Visual Studio 17 2022",
                "binaryDir": "${sourceDir}/build/${presetName}",
                "cacheVariables": {
                    "CMAKE_C_COMPILER": "cl",
                    "CMAKE_CXX_COMPILER": "cl",
                    "BUILD_TESTING": "ON",
                    "BUILD_SHARED_LIBS": "ON"
                }
            }
        ],
        "buildPresets": [
            {
                "name": "vs2022",
                "configurePreset": "vs2022"
            }
        ],
        "testPresets": [
            {
                "name": "vs2022",
                "configurePreset": "vs2022",
                "configuration": "Debug"
            }
        ]
    }
    

    兼容性

    我只能通过结合使用 Visual Studio 生成器和 MSVC 工具链来运行它。对于其他生成器(Ninja、Make 等),我总是遇到链接器错误,但无法弄清楚原因是什么。

    VS Code 会在测试资源管理器中显示测试(您可能需要 CMake Test Explorer 扩展名),但 Visual Studio 不会。我怀疑这是一个普遍的问题,VS 只能识别 add_test(&lt;name&gt; &lt;command&gt; &lt;args&gt;) 签名,但不能识别带有多配置生成器的 add_test(NAME &lt;name&gt; COMMAND &lt;command&gt; ...)。这是一个相关的bug report。但不幸的是,第一个签名是不够的,因为它不支持像 $&lt;TARGET_FILE:...&gt; 这样的生成器表达式。

    个人意见

    恕我直言,如果您可以选择使用哪个单元测试框架/库,我建议您再次使用 Microsoft 单元测试框架,原因如下:

    • 您将自己限制在 MSVC 工具链中。
    • 它是为 Visual Studio/MSBuild 量身定制的。将其集成到任何其他构建系统中是相当乏味的。
    • AFAIK 你甚至不能单独安装它,而只能将它作为 Visual Studio 的一部分安装。
    • 它不是跨平台的,所以你总是会被 Windows 卡住。

    我的建议是使用可以与不同编译器/工具链一起使用的跨平台的东西,可能是开源的,并且可以更好地与其他构建系统集成。示例包括 GTest、Catch、Boost.Test 等。有了这些,您可以使用单一配置生成器,例如Ninja 和 Visual Studio 中的测试资源管理器应该会发现它们。强调文本

    【讨论】:

    • 嘿 peter_w 感谢您的宝贵时间和您的好回答。我遇到了两个问题: - 1º:·$ENV{VCInstallDir} 不起作用。我不得不手动编写路径 - 2º:测试仅作为静态库运行。正如 FWK 共享的那样,它告诉我它无法在 .dll 上发现任何测试。此外,作为静态,没有日志出现,没有运行测试。只有绿色确认,但没有运行测试
    • 绝对不行。我只是继续复制粘贴您的完整工作示例。测试只是运行,但总是通过。我更改了值以使它们失败,但仍然通过。请注意,我使用的是 VS2022(也是 VsCode)。
    • 关于您的第一个问题,对于便携式 Find 模块,可能值得一看 vswhere。关于您的第二个问题,我可以确认,当构建为静态库时,测试总是通过,尽管我不知道为什么:/但是,当构建为共享库时,一切都按我的预期工作,至少在 VS Code 中.我已将我的CMakePresets.json 添加到答案中,也许对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-03
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    相关资源
    最近更新 更多