C++单元测试在运行所有测试或某个特定测试后失败

3

我正在使用GoogleTest进行单元测试。今天我添加了一个新的测试,发现当单独运行时它通过了测试,但是在运行所有测试时失败了。我已经阅读了一些问题和答案,但它们都与C#有关。

我使用C++和CMake进行这项工作。

我的CMakeLists.txt如下所示:

cmake_minimum_required(VERSION 2.8)

option(test "Build all tests." OFF)

set(EXECUTABLE_NAME proj)

project(${EXECUTABLE_NAME})

set(CMAKE_CXX_FLAGS "-g -Wall")

include_directories(src/main/cpp
                    ${Boost_INCLUDE_DIRS}
                    )

find_package(OpenCV REQUIRED core
                             imgproc
                             highgui
                             )
find_package(Boost REQUIRED COMPONENTS filesystem 
                                       system 
                                       regex 
                                       program_options
                                       )


  add_executable( ${EXECUTABLE_NAME}
# .........
                         )

  target_link_libraries(${EXECUTABLE_NAME} ${OpenCV_LIBRARIES}
                                           ${Boost_LIBRARIES}
                                           )

if (test)
  find_package(GTest REQUIRED)

  enable_testing()

  include_directories( ${GTEST_INCLUDE_DIRS} )

  add_executable(${EXECUTABLE_NAME}_test1
#  .............
            )

  add_executable(${EXECUTABLE_NAME}_test2
#  .............
            )  
  add_executable(${EXECUTABLE_NAME}_test3
#  .............
            )  
  add_executable(${EXECUTABLE_NAME}_test4
#  .............
            )

  target_link_libraries(${EXECUTABLE_NAME}_test1
                    ${OpenCV_LIBRARIES}
                    ${Boost_LIBRARIES}
                    ${GTEST_LIBRARIES}
                    gtest_main
                    pthread
                    )

  target_link_libraries(${EXECUTABLE_NAME}_test1
                    ${OpenCV_LIBRARIES}
                    ${Boost_LIBRARIES}
                    ${GTEST_LIBRARIES}
                    gtest_main
                    pthread
                    )
  target_link_libraries(${EXECUTABLE_NAME}_test2
                    ${OpenCV_LIBRARIES}
                    ${Boost_LIBRARIES}
                    ${GTEST_LIBRARIES}
                    gtest_main
                    pthread
                    )
  target_link_libraries(${EXECUTABLE_NAME}_test3
                    ${OpenCV_LIBRARIES}
                    ${Boost_LIBRARIES}
                    ${GTEST_LIBRARIES}
                    gtest_main
                    pthread
                    )
  target_link_libraries(${EXECUTABLE_NAME}_test4
                    ${OpenCV_LIBRARIES}
                    ${Boost_LIBRARIES}
                    ${GTEST_LIBRARIES}
                    gtest_main
                    pthread
                    )

  add_test(${EXECUTABLE_NAME}_test1
       ${EXECUTABLE_NAME}_test1
       )

  add_test(${EXECUTABLE_NAME}_test2
       ${EXECUTABLE_NAME}_test2
       )  
  add_test(${EXECUTABLE_NAME}_test3
       ${EXECUTABLE_NAME}_test3
       )  
  add_test(${EXECUTABLE_NAME}_test4
       ${EXECUTABLE_NAME}_test4
       )
endif()

我使用类似这样的测试:

#pragma once

#include <gtest/gtest.h>

#include "My.hpp"

/** Testing 
 */
TEST(qsdf, asdf)
{
 // ... initialization
 // ... test
}

我尝试使用 TEST_F 代替 TEST,但它崩溃了,它说 qsdf 没有被声明(我必须承认我以前没有做过很多单元测试)。

我读过其他测试会修改一些东西的可能性,我认为这是真的,因为如果我在运行其他测试后再单独运行某些测试,它会再次失败。

我的问题是:如何在 C++ 中使用 CMake 初始化每个测试(在 Linux 下,如果有影响的话)?

1个回答

3
这绝对是涉及共享资源的问题(正如您所怀疑的那样)。
每个测试的初始化都完全在测试文件中完成,没有任何额外的CMake等参与。正如您所提到的,测试通常由初始化阶段和实际测试组成。此外,包括一个清理步骤在测试完成后进行也并不罕见。例如:
TEST(qsdf, asdf)
{
    // ... initialization
    // ... test
    // ... **cleanup**
}

通常情况下,初始化和清理阶段仅涉及分配和释放测试中使用的变量。但这些阶段通常是为了准备运行测试,并在测试后进行清理。
如果您正在测试共享资源的代码,则初始化阶段包括根据需要初始化这些资源;清理阶段包括将这些资源重置回初始化阶段之前的状态。
当您有共享资源的测试时,使用测试夹具来协调资源的初始化/清理非常有帮助。这就是googletest中`TEST`和`TEST_F`宏之间的区别 - 后者代表基于测试夹具的测试。
googletest AdvancedGuide提供了大量关于使用测试夹具的信息:

https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#sharing-resources-between-tests-in-the-same-test-case

当您将TEST更改为TEST_F时,代码出现错误的原因是您没有定义测试夹具,而测试夹具是宏的第一个参数。在googletest中,测试夹具只是继承自::testing::Test类的类,因此您需要执行以下操作:
#pragma once

#include <gtest/gtest.h>

#include "My.hpp"

class MyTestFixture : public ::testing::Test
{
public:
    virtual void SetUp() // This is defined in ::gtest::Test and overridden here
    {
        // This code will run before every test that uses this fixture
    }

    virtual void TearDown() // This is defined in ::gtest::Test and overridden here
    {
        // This code will run after every test that uses this fixture
    }
};

/** Testing 
 */
TEST_F(MyTestFixture, asdf)
{
    // ... initialization (after SetUp)
    // ... test
    // ... cleanup (before TearDown)
}

是的,你说得对。但现在我想知道,如果我每次测试一个类,我该如何找出共享代码在哪里?确实,我使用一个类作为工具,它可能是吗?它只包含一些信息(2个向量)。我应该创建一个MyTestFixture而不是包含它的头文件吗?我不使用指针,只使用std::vector和cv::Mat,它们不需要释放。 - thedarkside ofthemoon
1
查找共享资源涉及浏览类中的所有代码,寻找外部值/对象。共享资源通常采用全局或静态变量的形式,但也可能发生其他类型的共享(例如,多个类写入同一文件)。还要记住,只有在至少一个类修改资源时,资源共享才会成为问题。一堆仅从共享变量中读取的类(或者如果变量是const)不会引起任何争用问题。至于测试夹具:我将它们定义在与测试相同的文件中,以提高可读性。 - Lilshieste
我不知道发生了什么...... 我在testX.cpp中有3个相似的TEST(...)失败。 如果我单独运行它,它会通过,但是如果我将其与所有其他测试一起运行,它会在中间的TEST失败(无论cpp在测试顺序中的位置如何)。 我发现如果只交换testX.cpp中的第一个和第二个TEST,则可以通过。这意味着什么? - thedarkside ofthemoon
很难在没有看到代码的情况下说出原因。你能否编辑你的问题,包括失败测试的代码? - Lilshieste

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接