【问题标题】:How to mock a legacy function without resorting to dependency injection?如何在不依赖注入的情况下模拟遗留函数?
【发布时间】:2019-12-09 23:54:51
【问题描述】:

给定以下假设的遗留生产代码:

struct Foo
{
     Bar bar;
     bool baz()
     {
         return !bar.qux();
     }
};

我如何模拟bar.qux(),以便它在一个测试中返回true,在另一个测试中返回false,而不使用dependency injection

我正在使用Google Test 框架,但希望避免为依赖注入添加太多接口。为了可测试性而使用过多的接口往往会使生产代码过于复杂。

【问题讨论】:

  • 如果您不想在运行时通过依赖注入执行此操作,那么您可以通过链接替代实现来执行链接时间。

标签: c++ unit-testing googletest


【解决方案1】:

我们大概可以这样做:

#include <iostream>
#include <vector>
#include <deque>

// test/MockBarMonitorsAndControls.hpp
namespace test
{
    bool const Bar_qux_default_output = true;
    std::deque<bool> Bar_qux_outputs;
    std::vector<int> Bar_qux_arg0_inputs;
}

// production/Bar.hpp
struct Bar
{
    bool qux(int x);
};

// production/Bar.cpp
// bool Bar::qux(int x)
// {
//    return static_cast<bool>(x & 2);
// }

// test/Bar.cpp
bool Bar::qux(int x)
{
    test::Bar_qux_arg0_inputs.push_back(x);

    if (!test::Bar_qux_outputs.empty())
    {
        auto result = test::Bar_qux_outputs.front();
        test::Bar_qux_outputs.pop_front();
        return result;
    }
    else
    {
        return test::Bar_qux_default_output;
    }
}

// production/Foo.hpp
struct Foo
{
    Bar bar;
    int x = 9;
    bool baz()
    {
        return !bar.qux(x);
    }

    void henry();
};

// test/BarTest.cpp
void TestBar1()
{
    test::Bar_qux_outputs.clear();
    test::Bar_qux_arg0_inputs.clear();

    test::Bar_qux_outputs.push_back(false);

    Foo foo;
    bool pass = true;

    auto result = foo.baz();
    if (!result)
    {
        std::cout << "TEST1_ERROR: expected true result" << std::endl;
        pass = false;
    }

    auto input = test::Bar_qux_arg0_inputs.front();
    if (input != 9)
    {
        std::cout << "TEST1_ERROR: expected arg0 to be 9 but got " << input << std::endl;
        pass = false;
    }

    if (pass)
    {
        std::cout << "TEST1 PASS" << std::endl;
    }
    else
    {
        std::cout << "TEST1 FAIL" << std::endl;
    }
}

// test/BarTest.cpp
void TestBar2()
{
    test::Bar_qux_outputs.clear();
    test::Bar_qux_arg0_inputs.clear();

    test::Bar_qux_outputs.push_back(true);

    Foo foo;
    foo.x = 21;

    bool pass = true;

    auto result = foo.baz();
    if (result)
    {
        std::cout << "TEST2_ERROR: expected false result" << std::endl;
        pass = false;
    }

    auto input = test::Bar_qux_arg0_inputs.front();
    if (input != 21)
    {
        std::cout << "TEST2_ERROR: expected arg0 to be 21 but got " << input << std::endl;
        pass = false;
    }

    if (pass)
    {
        std::cout << "TEST2 PASS" << std::endl;
    }
    else
    {
        std::cout << "TEST2 FAIL" << std::endl;
    }
}

int main()
{
    TestBar1();
    TestBar2();
    return 0;
}

这是示例输出:

TEST1 PASS
TEST2 PASS

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2020-12-08
    相关资源
    最近更新 更多