gpt4 book ai didi

c++ - 来自外部类的模拟静态方法(我无法更改!)

转载 作者:行者123 更新时间:2023-12-01 14:42:11 39 4
gpt4 key购买 nike

我想模拟(使用 gmock)来自我无法更改的类的静态函数。
A 是我要模拟的类:

Class A
{
public:
static std::string get_id();
...
}
B 是我想用 gmock 测试的类(class):
Class B
{
public:
B(A *a_ptr);
...

std::string foo();
private:
A *m_a_ptr;
}

B::B(A *a_ptr) : m_a_ptr(a_ptr)
{
}

std::string B::foo()
{
id = m_a_ptr->get_id();
return id;
}
如何在不更改 A 类的情况下模拟 get_id 方法?

最佳答案

静态依赖注入(inject)和 GMock 委托(delegate)
我们将首先将您的示例最小化为以下内容(以使后面的段落尽可能不嘈杂):

// a.h
#include <string>

// class to mock
class A {
static std::string get_id();
};

// b.h
#include <string>
#include "a.h"

// class that use A
struct B {
std::string foo() const {
return A::get_id();
}
};
虽然你不能改变 A ,您可以更改 B静态注入(inject) A在产品代码中,而您可以静态注入(inject) A 的模拟委托(delegate)对于测试代码:
// b.h
#include <string>
#include "a.h"

namespace detail {
// The type template parameter is set to A by default,
// and should not need to override this default type
// in production code, but can be injected with
// mocked classes in test code.
template<typename AImpl = ::A>
struct BImpl {
std::string foo() const {
return A::get_id();
}
};
} // namespace detail

// Expose product-intent specialization.
using B = BImpl<>;
A 的模拟在哪里使用静态(非线程安全)方法来模拟对注入(inject)静态类型的调用:
// a_mock.h
#include <memory>
#include <string>
#include "gmock/gmock.h"

class AMock {
// Mocked methods.
struct Mock {
MOCK_CONST_METHOD0(get_id,
std::string());
};

// Stubbed public API for static function of object under test:
// delegates stubbed calls to the mock.
static std::string get_id() {
if (const auto mock = mock_.lock()) {
mock->get_id();
}
else {
ADD_FAILURE()
<< "Invalid mock object! The test can no "
"longer be considered useful!";
}
}

// Public setter to specify the mock instance used in test (which in
// turn will be the instance that Google Test's EXPECTS and mocked
// calls is placed upon).
static void setMock(const std::shared_ptr<Mock>& mock) { mock_ = mock; }

private:
// Pointer to mock instance.
static std::weak_ptr<Mock> mock_;
};
最后,它可以用于 BImpl 的测试如下:
// b_test.cpp
#include "b.h" // object under test
#include "gmock/gmock.h"
#include "a_mock.h"

class BImplTest : public ::testing::Test {
public:
using BImplUnderTest = BImpl<AMock>;

BImplTest() : amock_(std::make_shared<AMock::Mock>()) {
AMock::setMock(amock_);
}
};

TEST_F(BImplTest, foo) {
// Setup mocked call(s).
EXPECT_CALL(amock_, foo()).WillOnce(::testing::Return( /*...*/ ));

// Call object under test.
BImplUnderTest b{};
b.foo();

}

进一步隐藏 B 的事实实际上是类模板的特化 BImpl如果你开始大量使用这种模式(在不同的子程序上以滑动窗口的方式)并且想要避免单个大而臃肿的翻译单元,你可以移动 detail::B 的成员函数的定义。用于分隔标题的类模板,例如 b-timpl.h (包括 b.h )和与 b.h 关联的源文件中,比如说 b.cpp , 包括 b-timpl.h而不是 b.h并为生产意图添加显式实例化定义 detail::BImpl特化:
// b.cpp
template class ::detail::BImpl<>;
而在 ::detail::BImpl 的测试中你包括 b-timpl.h而不是 b.h并为类模板的模拟注入(inject)特化添加显式实例化定义:
// b_test.cpp
#include "b-timpl.h"
// ...

template class ::detail::BImpl<AMock>;

// ...
为什么? BImpl类未参数化以允许其接口(interface)的用户静态注入(inject)不同的行为(对于用户意图,用户应该只看到 B ),但允许在测试时注入(inject)模拟或 stub 类。

关于c++ - 来自外部类的模拟静态方法(我无法更改!),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63630216/

39 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com