如何解决从外部类模拟静态方法我不能更改! 静态依赖注入和GMock委托进一步隐藏了// 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&
我想(用gmock)模拟我不能更改的类的静态函数。 A是我要模拟的类:
Class A
{
public:
static std::string get_id();
...
}
B是我要通过gmock测试的班级:
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方法?
解决方法
静态依赖注入和GMock委托
我们将首先将您的示例最小化为以下内容(以使后面的段落尽可能不引起干扰):
// 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
更改为产品代码中的静态注入 A
,而您可以静态注入{ {1}}用于测试代码:
A
// 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
最后可以在// 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
的特殊化这一事实
如果您开始大量使用此模式(在不同的子例程上以滑动窗口的方式使用)并希望避免使用单个又大又肿的翻译单元,则可以移动{{1}的成员函数的定义}类模板以分隔标头,例如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
类未进行参数化,以允许其界面的用户静态注入不同的行为(出于用户意图,用户应仅查看// b_test.cpp
#include "b-timpl.h"
// ...
template class ::detail::BImpl<AMock>;
// ...
),但允许在测试时注入模拟或存根类。 / p>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。