是否可以在不同的源文件中分发单元测试模块,如果我使用Boost.Test?



我有许多使用Boost的测试源文件。测试和我试图运行它们,但得到multiple definition of boost::unit_test::runtime_config::argument_store()错误和这个库的许多模块相同。

例如,有两个文件:test_size.cpp

#define BOOST_TEST_MODULE Test_Repeats
#include "../include/test_config.h"
BOOST_AUTO_TEST_CASE(test_repeats) {
int n = 30;
Repeats r = Repeats(n);
BOOST_REQUIRE(r.rep == n);
}

test_repeats.cpp:

#define BOOST_TEST_MODULE Test_Size
#include "../include/test_config.h"
BOOST_AUTO_TEST_CASE(test_size) {
int n = 20;
int m = 30;
Size sz = Size(n, m);
BOOST_REQUIRE(sz.n == n && sz.m == m);
}

test_config.h:

#include <boost/test/included/unit_test.hpp>
#include "../include/size.h"
#include "../include/repeats.h"

这是我的Makefile运行测试:

FAST_HEADERS := $(wildcard Fast/**/*.h)
FAST_TEST_SOURCES := $(filter-out Fast/src/main.cpp, $(wildcard Fast/src/*.cpp Fast/tests/test_size.cpp Fast/tests/test_repeats.cpp))
FAST_TEST_OBJECTS := ${FAST_TEST_SOURCES:.cpp=.o}
fast_test: $(FAST_TEST_OBJECTS)
g++ $(FAST_TEST_OBJECTS) -lboost_unit_test_framework -o fast_test 
./fast_test
%.o: Fast/**/%.cpp  $(FAST_HEADERS)
g++ $@ -o $< 

我知道有可能在一个源文件中有所有的测试,它会工作得很好,但我很好奇是否有可能在不同的源文件中分发所有的测试单元,使其更结构化。

有什么问题和我Makefile或源文件吗?

%.o: Fast/**/%.cpp  $(FAST_HEADERS)
g++ $@ -o $< 

由于**,这永远不适用。你还反转了$@$<。你可以使用

Fast/tests/%.o: Fast/tests/%.cpp | $(FAST_HEADERS)
Fast/src/%.o: Fast/src/%.cpp | $(FAST_HEADERS)
%.o: %.cpp
g++ -o $@ $<

真正的问题

也就是说,让我们找出链接器消息的问题所在。老实说,我花在上的时间远比我愿意承认的"偶然"多得多。找到它。首先,我显然使用了文档,主要是:

  • https://www.boost.org/doc/libs/1_53_0/libs/test/doc/html/utf/user-guide/test-runners.html
  • 特别是关于UTF的动态库变体"这有用地提到了

    对于一个多文件测试模块标志不能在makefile中定义,必须只在一个测试文件中定义,以避免函数main()的重复副本。

还有一些邮件列表/SO的帖子:

  • boost test library: Multiple definition error
  • Boost Test Error: main已经定义
  • 和其他

老实说,我学到的唯一切实的东西是

  • BOOST_TEST_MODULE只打算在整个测试可执行文件中定义一次

然而,其他记录的标志BOOST_TEST_DYN_LINKBOOST_TEST_NO_MAIN没有任何影响。经过反复试验和预处理器#error调试后,我发现这些符号在包含

后都只是undef
#include <boost/test/included/unit_test.hpp>

我没有立即认出/included/部分。一时兴起,我想改成:

#include <boost/test/unit_test.hpp>

工作,但现在main未定义。因此,我提出了以下重构的makefile和一个额外的Fast/tests/module.cpp来定义main。毫无疑问,这一切仍然不是完全理想的。例:我认为,既然你正在链接动态库,BOOST_TEST_DYN_LINK应该被定义,但它似乎没有¯()/¯.

因此,这里显示的Makefile的一部分是为了在需要时如何实现特定高级任务的灵感。

test: # make default target
FAST_HEADERS := $(wildcard Fast/**/*.h)
FAST_TEST_SOURCES := $(filter-out Fast/src/main.cpp, $(wildcard Fast/src/*.cpp Fast/tests/*.cpp))
FAST_TEST_OBJECTS := ${FAST_TEST_SOURCES:.cpp=.o}
CPPFLAGS+= $(INCLUDES)
CPPFLAGS+= -D BOOST_TEST_DYN_LINK
CXXFLAGS+= -std=c++11 $(CPPFLAGS)
LDFLAGS+= -lboost_unit_test_framework
Fast/tests/test_%.o: CPPFLAGS+=-DBOOST_TEST_NO_MAIN
Fast/tests/%.o: Fast/tests/%.cpp | $(FAST_HEADERS)
Fast/src/%.o: Fast/src/%.cpp | $(FAST_HEADERS)
%.o: %.cpp
g++ $(CXXFLAGS) -o $@ -c $<
fast_test: $(FAST_TEST_OBJECTS)
g++ $(CXXFLAGS) $^ $(LDFLAGS) -o $@
test: fast_test
./$<
.PHONY: test

使用make -Bsn测试显示了标志如何组合:

g++ -std=c++11  -D BOOST_TEST_DYN_LINK -o Fast/src/size.o -c Fast/src/size.cpp
g++ -std=c++11  -D BOOST_TEST_DYN_LINK -o Fast/src/repeats.o -c Fast/src/repeats.cpp
g++ -std=c++11  -D BOOST_TEST_DYN_LINK -DBOOST_TEST_NO_MAIN -o Fast/tests/test_size.o -c Fast/tests/test_size.cpp
g++ -std=c++11  -D BOOST_TEST_DYN_LINK -DBOOST_TEST_NO_MAIN -o Fast/tests/test_repeats.o -c Fast/tests/test_repeats.cpp
g++ -std=c++11  -D BOOST_TEST_DYN_LINK -o Fast/tests/module.o -c Fast/tests/module.cpp
g++ -std=c++11  -D BOOST_TEST_DYN_LINK Fast/src/size.o Fast/src/repeats.o Fast/tests/test_size.o Fast/tests/test_repeats.o Fast/tests/module.o
-lboost_unit_test_framework -o fast_test
./fast_test

例如./fast_test -l all:

的输出
Running 2 test cases...
Entering test module "Fast_Tests"
Fast/tests/test_size.cpp(3): Entering test case "test_size"
Fast/tests/test_size.cpp(8): info: check sz.n == n && sz.m == m has passed
Fast/tests/test_size.cpp(3): Leaving test case "test_size"; testing time: 136us
Fast/tests/test_repeats.cpp(3): Entering test case "test_repeats"
Fast/tests/test_repeats.cpp(7): info: check r.rep == n has passed
Fast/tests/test_repeats.cpp(3): Leaving test case "test_repeats"; testing time: 125us
Leaving test module "Fast_Tests"; testing time: 311us
*** No errors detected

收场

我保持了"测试驱动";Size/Repeats头文件的实现。如果要在实际代码中更改,则需要链接依赖对象。

对于我没有解释的GNU Make特性,请参阅https://www.gnu.org/software/make/manual/

代码转储:

  • FileMakefile

    test: # make default target
    FAST_HEADERS := $(wildcard Fast/**/*.h)
    FAST_TEST_SOURCES := $(filter-out Fast/src/main.cpp, $(wildcard Fast/src/*.cpp Fast/tests/*.cpp))
    FAST_TEST_OBJECTS := ${FAST_TEST_SOURCES:.cpp=.o}
    CPPFLAGS+= $(INCLUDES)
    CPPFLAGS+= -D BOOST_TEST_DYN_LINK
    CXXFLAGS+= -std=c++11 $(CPPFLAGS)
    LDFLAGS+= -lboost_unit_test_framework
    Fast/tests/test_%.o: CPPFLAGS+=-DBOOST_TEST_NO_MAIN
    Fast/tests/%.o: Fast/tests/%.cpp | $(FAST_HEADERS)
    Fast/src/%.o: Fast/src/%.cpp | $(FAST_HEADERS)
    %.o: %.cpp
    g++ $(CXXFLAGS) -o $@ -c $<
    fast_test: $(FAST_TEST_OBJECTS)
    g++ $(CXXFLAGS) $^ $(LDFLAGS) -o $@
    test: fast_test
    ./$<
    .PHONY: test
    
  • FileFast/include/repeats.h

    #pragma once
    struct Repeats {
    explicit Repeats(int n) : rep(n){}
    int const rep;
    };
    
  • FileFast/include/size.h

    #pragma once
    struct Size {
    explicit Size(int n, int m)
    : n(n)
    , m(m)
    {
    }
    int const n, m;
    };
    
  • FileFast/include/test_config.h

    #include <boost/test/unit_test.hpp>
    #include "../include/size.h"
    #include "../include/repeats.h"
    
  • FileFast/src/main.cpp

  • FileFast/src/repeats.cpp

  • 文件Fast/src/size.cpp
  • FileFast/tests/module.cpp

    #define BOOST_TEST_MODULE Fast_Tests
    #include <boost/test/included/unit_test.hpp>
    
  • 文件Fast/tests/test_repeats.cpp

    #include "../include/test_config.h"
    BOOST_AUTO_TEST_CASE(test_repeats)
    {
    int n = 30;
    Repeats r = Repeats(n);
    BOOST_REQUIRE(r.rep == n);
    }
    
  • 文件Fast/tests/test_size.cpp
  • #include "../include/test_config.h"
    BOOST_AUTO_TEST_CASE(test_size)
    {
    int n = 20;
    int m = 30;
    Size sz = Size(n, m);
    BOOST_REQUIRE(sz.n == n && sz.m == m);
    }
    

相关内容

  • 没有找到相关文章

最新更新