【问题标题】:Linking in test libraries with CppUnit使用 CppUnit 链接测试库
【发布时间】:2010-11-04 05:03:33
【问题描述】:

我正在使用 CppUnit 设置一堆单元测试,但遇到的问题是没有一个测试正在运行。该项目分为几个小库,我计划以相同的方式划分单元测试类,然后将它们全部链接到一个单独的测试程序中。问题是,然后测试类在他们自己的库中,除非我明确调用它们,否则它们不会链接到主测试程序中,即我必须放入

runner.addTest( TestClass::suite() );

单独针对每个测试类,不能使用 TestFactoryRegistry 的 makeTests() 方法来获取测试列表。如果我只是在顶层目录中将它们全部编译在一起,makeTests() 方法可以正常工作,但如果我能提供帮助,我不想将所有测试类放在一个位置。

CppUnit 文档给出了以下小提示

使用 Helper 时的链接问题 宏?

当你创建一个项目并编写 它的单元测试套件,工作已经完成 通过使用更容易 所谓的辅助宏: CPPUNIT_TEST_SUITE_NAMED_REGISTRATION, CPPUNIT_REGISTRY_ADD 和 CPPUNIT_REGISTRY_ADD_TO_DEFAULT。这 问题是如果你使用那些 源代码文件中的宏 TestFixture 类(比如 MyTest 作为 示例),如果您使用类似的行 这个

runner.addTest( CppUnit::TestFactoryRegistry::getRegistry().makeTest()

);

在文件中的 main() 函数中 main.cpp,不会有试运行 完全没有!

原因很简单,链接 阶段,构建的步骤之一 过程中,不要插入对象 最终文件(.obj 或 .o 文件) 如果没有未定义则可执行 main.cpp 中的符号。

这样,目标代码 包含 AutoRegister 静态 变量实例化不属于 最终的可执行文件并且无法 将自己插入跑步者中 main() 函数。

你必须创建一个未定义的符号 在 main.cpp 中使 mytest.o 文件 与 main.o 集成到 最终可执行文件。

米歇尔·诺拉德的诡计

但没有说明如何进行这项工作,而且我只是太密集了,无法自己弄清楚或在网上找到示例。

现在我可以为每个库进行单独的可执行测试,最后我可能会这样做,但我想先尝试让它工作,所以我只运行一个测试程序来测试整个事物。有关如何使其发挥作用的任何想法/示例?

【问题讨论】:

    标签: c++ linux unit-testing cppunit


    【解决方案1】:

    我意识到这篇文章现在已经很老了,但是对于遇到它的其他人来说: 在代码中没有引用的情况下解决此问题的一种方法是指示(强制)链接器将整个静态库包含在二进制文件中。 gcc 和 ld 手册页中提供了详细信息区域,这篇文章也涵盖了它: How to force gcc to link unreferenced, static C++ objects from a library

    根据 ld 的手册页,考虑明确关闭该选项很重要(也显示在上面的示例之一中)。

    【讨论】:

      【解决方案2】:

      这个问题的解决方案就像之前所说的那样简单(但可能不是很优雅)。 对于位于外部库中的每个 TestFixture,您必须在主模块中添加以下两行代码

      #include <CppUnitTestFixtureExample.h>
      CppUnitTestFixtureExample Test1;
      

      它创建了一个未使用的虚拟变量,它只是强制链接器链接测试夹具。现在位于主模块中的测试运行器可以运行测试了。

      【讨论】:

        【解决方案3】:

        通过向 main 添加一个未定义的符号,他只是意味着创建任何随机外部符号来强制链接器搜索包含测试代码的外部库。

        例如,假设有两个测试库 fred 和 barney,你只需在 fredTestLib.cpp 中添加这一行:

        int fredDummyInt = 0; // declare a unique symbol for the linker to resolve
        

        在 barneyTestLib.cpp 中,您将添加类似的行:

        int barneyDummyInt = 0; // a different unique symbol for the linker to resolve
        

        您可以在不同的步骤中分别编译每个库。然后在主测试程序中强制链接器解析它们。所以将这些行添加到 main.cpp:

        extern int fredDummyInt;
        extern int barneyDummyInt;
        ...
        main () {
            ...
            fredDummyInt++; // give the linker some symbols to resolve
            barneyDummyInt++;
            ...
        

        这个想法(根据上述技巧的作者所说)是因为链接器已经在 fredTest.lib 中搜索 fredDummyInt,它也会找到并解决您自动注册的测试。

        注意:我没有试过这个,看看它是否有效!我只是在回答你关于外部的问题。

        要考虑的另一种方法是在 DLL 中创建测试,并使用 LoadLibrary() 显式地使它们运行。对于矫枉过正,如果你使用 MfcUi::TestRunner,你可能会构建一个小的下拉 GUI 东西,让你选择要加载的库,加载它,然后显示要在该库中运行的测试,然后运行它们。

        【讨论】:

        • 它几乎按照我想要的方式工作。添加它会导致注册系统从包含外部变量的文件中提取测试,而不是从库中的所有测试中提取测试。库中有大约十几个类(每个类都在它们自己的文件中),它只为变量所在的一个类进行测试。这实际上可能是正确的行为,但除了单独包含每个类之外并没有给我带来任何好处。我非常希望这会奏效。
        • 好吧,你正试图在没有代码的情况下获得“神奇”的结果,虽然我赞扬你的尝试,但在某些时候我们都必须编写代码来完成工作。我完全同意自我维护代码是最好的类型(它“正常工作”的东西),但你希望在这里超越单个模块的边界,这就是它必须变得棘手的地方。链接器应该如何知道何时停止引入新库?它应该搜索你的整个硬盘吗?当前文件夹?子文件夹?路径文件夹?必须有合理的限制,超出这些限制,您必须具体。
        猜你喜欢
        • 2010-09-22
        • 1970-01-01
        • 2013-04-09
        • 1970-01-01
        • 2011-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多