3

我已经为 c++ 创建了一个单元测试框架,我想稍后将其移植到 C 中,但我遇到了一个单元测试根本无法运行的问题。单元测试在 .cpp 文件中创建,并且只有一个 .cpp 文件应该运行所有测试。

为了简化一点,这是通常创建测试的方式:

主文件

#define UNIT_TEST_IMPL // or whatever
#include "unit_test.hpp"

int main()
{
    for(const auto& test : tests_queue)
        test->run();
    return 0;
}

unit_test.hpp

#pragma once

struct Base
{
protected:
    Base() = delete;
    Base(Base* ptr);

public:
    virtual void run() = 0;
};

#if defined(UNIT_TEST_IMPL)

#include <vector>

std::vector<Base*> tests_queue;

Base::Base(Base* ptr)
{
    tests_queue.push_back(ptr);
}

#endif

测试.cpp

#include "unit_test.hpp"

#include <iostream>

struct Test : Base
{
    Test()
        : Base(this)
    {}

    void run() override
    {
        std::cout << "new test" << std::endl;
    }

};

struct Test2 : Base
{
    Test2()
        : Base(this)
    {}

    void run() override
    {
        std::cout << "new test2" << std::endl;
    }
};

static Test test;
static Test2 test2;

问题是:为什么它不运行 test.cpp 中定义的测试(如果我在 main.cpp 文件中创建测试,它们运行得很好)?我的猜测是问题出在我存储基指针的方式上,但我不知道。编译器是g++ 6.4.0

4

2 回答 2

4

静态初始化订单惨败在行动:

全局跨翻译单元的初始化顺序是未指定的,因此如果test,test2在 之前实例化tests_queue,则后面的初始化将破坏注册。

一种可能的修正:

#pragma once

struct Base
{
protected:
    Base();

public:
    virtual ~Base() = default;
    virtual void run() = 0;
};

#if defined(UNIT_TEST_IMPL) // Should be defined only once.

#include <vector>

std::vector<Base*>& get_tests_queue()
{
    static std::vector<Base*> tests_queue;
    return tests_queue;
}

Base::Base()
{
    get_tests_queue().push_back(this);
}

#endif

所以你的 main.cpp 将是:

#define UNIT_TEST_IMPL // or whatever
#include "unit_test.hpp"

int main()
{
    for(const auto& test : get_tests_queue())
        test->run();
}

您的 unitTests 将不会被修改:

#include "unit_test.hpp"

#include <iostream>

struct Test : Base
{
    void run() override { std::cout << "new test" << std::endl; }
};

struct Test2 : Base
{
    void run() override { std::cout << "new test2" << std::endl; }
};

static Test test;
static Test2 test2;

演示

于 2018-06-07T17:48:31.550 回答
0

我的赌注是某种形式的静态初始化惨败

不确定,但您不能指望全局变量(您在 test.cpp 中定义的 Test1 和 Test2 变量在 Main 运行之前被初始化。

根据经验,如果可以(在这种情况下,您可能可以),请避免使用全局变量。

但主要是,您的程序不应该对全局/静态变量的初始化顺序做出任何假设。在这里,您假设两个全局变量在 main 之前初始化。可能,他们不是

于 2018-06-07T18:40:11.840 回答