为什么link顺序会影响使用宏的测试的测试结果?
Why does link order affect the test result of a test that uses macros?
我正在使用 Google 测试和 Google 模拟来使用测试驱动开发编写代码。我正在为 Google 测试编写一个小的 "plugin"。为了确保测试会在预期的正确消息时失败,我创建了一个简单的 FailureReporter
class ,我将子 class 并在插件中注入模拟版本以捕获结果并与预期值进行比较。
本着 TDD 极端主义的精神,我还编写了一个测试来确保 FailureReporter
有效。为此,我 "replaced" FAIL()
宏是为了不导致失败,而是为了捕获生成的错误消息。然而,这就是事情变得奇怪的地方。它在一台机器上工作,但在另一台机器上不工作。在寻找原因时,我发现可以通过更改 link 顺序来修复它。这看起来很奇怪,因为 "fix" 是使用宏完成的,我认为它会在编译时进行硬编码,并且 link 不会有什么不同。
我发现:link测试本身没有问题。将它与使用 FailureReporter 的模拟版本的测试链接只有在另一个测试在 FailureReporterTest.
之后 linked 时才有效 为什么会发生这种情况?
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
和link将它们与
g++ DummyTest.o FailureReporterTest.o -pthread -lgtest -lgmock -lgmock_main
生成未通过 failMethod 测试的 a.out 可执行文件,同时 link 使用
对它们进行测试
g++ FailureReporterTest.o DummyTest.o -pthread -lgtest -lgmock -lgmock_main
生成成功通过两个测试的 a.out 可执行文件。为什么?
class FailureReporter {
public:
virtual void fail(const char* errorMessage) {
/* code */
创建 FailureReporter::fail
的隐式 inline
实现。
inline
函数被导出。如果 linker 看到两个同名同类型的 inline
函数,它会默默地丢弃一个。如果它们实际上不相同,那么您的程序格式不正确,不需要诊断。
当您仅在一个编译单元中重新定义 FAIL()
并在其他编译单元中重新定义 link 时,您最终会得到两个 FailureReporter::fail
的定义。他们 link 和未定义的行为结果。在你的情况下,你在两种情况下都会得到其中之一 运行,确定了 linker 选择丢弃内联冲突的任意规则。看起来像 'keep first one I see'.
我正在使用 Google 测试和 Google 模拟来使用测试驱动开发编写代码。我正在为 Google 测试编写一个小的 "plugin"。为了确保测试会在预期的正确消息时失败,我创建了一个简单的 FailureReporter
class ,我将子 class 并在插件中注入模拟版本以捕获结果并与预期值进行比较。
本着 TDD 极端主义的精神,我还编写了一个测试来确保 FailureReporter
有效。为此,我 "replaced" FAIL()
宏是为了不导致失败,而是为了捕获生成的错误消息。然而,这就是事情变得奇怪的地方。它在一台机器上工作,但在另一台机器上不工作。在寻找原因时,我发现可以通过更改 link 顺序来修复它。这看起来很奇怪,因为 "fix" 是使用宏完成的,我认为它会在编译时进行硬编码,并且 link 不会有什么不同。
我发现:link测试本身没有问题。将它与使用 FailureReporter 的模拟版本的测试链接只有在另一个测试在 FailureReporterTest.
之后 linked 时才有效 为什么会发生这种情况?
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
和link将它们与
g++ DummyTest.o FailureReporterTest.o -pthread -lgtest -lgmock -lgmock_main
生成未通过 failMethod 测试的 a.out 可执行文件,同时 link 使用
对它们进行测试g++ FailureReporterTest.o DummyTest.o -pthread -lgtest -lgmock -lgmock_main
生成成功通过两个测试的 a.out 可执行文件。为什么?
class FailureReporter {
public:
virtual void fail(const char* errorMessage) {
/* code */
创建 FailureReporter::fail
的隐式 inline
实现。
inline
函数被导出。如果 linker 看到两个同名同类型的 inline
函数,它会默默地丢弃一个。如果它们实际上不相同,那么您的程序格式不正确,不需要诊断。
当您仅在一个编译单元中重新定义 FAIL()
并在其他编译单元中重新定义 link 时,您最终会得到两个 FailureReporter::fail
的定义。他们 link 和未定义的行为结果。在你的情况下,你在两种情况下都会得到其中之一 运行,确定了 linker 选择丢弃内联冲突的任意规则。看起来像 'keep first one I see'.