为什么链接顺序会影响使用宏的测试的测试结果?

时间:2015-04-12 16:05:09

标签: c++ linker c-preprocessor googletest googlemock

我使用Google Test和Google Mock使用测试驱动开发编写代码。我正在写一个小插件"用于Google Test。为了确保测试在预期时使用正确的消息失败,我创建了一个简单的FailureReporter类,我将子类并在插件中注入模拟版本以捕获结果并与预期值进行比较。

本着TDD极端主义的精神,我还写了一个测试来确保FailureReporter有效。要做到这一点,我已经取代了#34; FAIL()宏,以便不会导致失败但捕获生成的错误消息。但是,这就是事情变得奇怪的地方。它在一台机器上工作,但在另一台机器上工作。在搜索原因时,我发现可以通过更改链接顺序来修复它。这看起来很奇怪,因为"修复"是使用宏完成的,我认为它在编译时会被硬编码,并且链接它不会产生影响。

我发现的是:连接测试本身不会导致任何问题。将它与使用模拟版本的FailureReporter的测试相关联,只有在FailureReporterTest.为什么会发生这种情况后链接另一个测试时才有效?

FailureReporter.hpp:

#ifndef FAILURE_REPORTER_H
#define FAILURE_REPORTER_H

#include "gtest/gtest.h"

class FailureReporter {
public:
    virtual void fail(const char* errorMessage) {
        FAIL() << errorMessage;
    }
};

#endif

FailureReporterTest.cpp:

#include <sstream>

#include "gtest/gtest.h"

static std::stringstream* failStream;

#ifdef FAIL
#undef FAIL
#endif

#define FAIL() *failStream << ""

#include "FailureReporter.hpp"

TEST(FailureReporterTest, failMethod) {
    const char* errorMessage = "Test error message";
    FailureReporter *reporter;
    std::stringstream stream;

    failStream = &stream;

    reporter = new FailureReporter();

    reporter->fail(errorMessage);

    EXPECT_STREQ(errorMessage, stream.str().c_str());

    delete reporter;
}

MockFailureReporter.cpp

#ifndef MOCK_FAILURE_REPORTER_HPP
#define MOCK_FAILURE_REPORTER_HPP

#include "gmock/gmock.h"

#include "FailureReporter.hpp"

class MockFailureReporter : public FailureReporter {
public:
    MOCK_METHOD1(fail, void(const char*));
};

#endif

DummyTest.cpp

#include "gtest/gtest.h"

#include "MockFailureReporter.hpp"

TEST(DummyTest, dummy) {
    new MockFailureReporter();
    SUCCEED();
}

使用

编译源代码
g++ -c DummyTest.cpp
g++ -c FailureReporterTest.cpp

并将它们与

相关联
g++ DummyTest.o FailureReporterTest.o -pthread -lgtest -lgmock -lgmock_main

生成一个未通过failMethod测试的a.out可执行文件,同时将它们与

链接
g++ FailureReporterTest.o DummyTest.o -pthread -lgtest -lgmock -lgmock_main

生成一个可执行两次测试的a.out可执行文件。为什么呢?

1 个答案:

答案 0 :(得分:2)

class FailureReporter {
public:
  virtual void fail(const char* errorMessage) {
    /* code */

创建inline的隐式FailureReporter::fail实现。

导出

inline个函数。如果链接器看到两个具有相同名称和类型的inline函数,它将以静默方式丢弃一个。如果它们实际上不相同,那么您的程序就会形成,并且不需要诊断。

当您仅在一个编译单元中重新定义FAIL()并将其与其他编辑单元链接时,最终会得到FailureReporter::fail的两个定义。它们链接,并且未定义的行为结果。在您的情况下,您可以在两种情况下运行其中一个,确定链接器选择丢弃内联冲突的任意规则。这看起来像'保留我看到的第一个'。