微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从外部类模拟静态方法我不能更改! 静态依赖注入和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委托进一步隐藏了// 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 举报,一经查实,本站将立刻删除。