Gtest和gmock在下面的代码片段中出现错误



如何实现私有受保护成员函数的gtest或gmock。我是gtest和gmock的新手。下面是我需要在尝试的同时执行gtest或gmock的代码。

constexpr static char _session[]{"S_ID"};
typedef struct {
int  session;
} Session;
typedef std::function<void(const Session &)> SessionCallback_t;
class Service : public ParentService {
public:
Service();
void registerCallback(const SessionCallback_t & callback);
protected:
virtual void notifyHandler(const Json::Value & data) override;
virtual void notifyState();
private:

Session mSession;
SessionCallback_t mCallback;
void jsonParse(const Json::Value & json_data);
};

不编译的My Attemp

class TestService : public Service {
public:
TestService(): Service() {
}
bool registerCallback(const SessionCallback_t & cb) {
// how to achive this?

}

};

class MyTestService : public ::testing::Test {

protected:
virtual void SetUp() {
}
virtual void TearDown() {

}
};

TEST_F(MyTestService , registerCallbackTest) {
TestService service;
EXPECT_TRUE(service.registerCallback(SessionCallback_t));

}   

我被下面的界面卡住了

1.registerCallback((

2.notifyHandler((

3.notifyState((

4.jsonParse((

请稍等片刻再继续。

欢迎使用堆栈溢出!

首先,让我推荐CppCast最近的一期关于测试设计的文章。播客指出,如果你发现你的代码很难测试,那就意味着它耦合得太紧密,因此设计得很差。

它还(正确地,IMHO(建议您只测试公共函数。如果您发现自己需要测试私有函数,那么您可能应该重构代码。

一种方法是将代码分解为多个类,这些类包含要测试的公共函数。然后,您的复合类可以直接创建并拥有该类(如果它是一个没有依赖项或自身复杂资源(如向量或字符串类(的基本类型,则适用(,也可以使用依赖项注入将依赖项作为构造函数或方法参数传入(适用于数据库、网络连接、文件系统等(

然后在测试中,您传入一个测试替身,例如一个模拟对象或一个简化的实现,如内存中数据库,而不是进程外数据库连接,它的行为与对象类似,但在测试情况下可以满足您的需要。

这是最基本的建议。在您的特定情况下,看起来您正试图覆盖TestService中的一个非虚拟函数。你到底想测试什么?

我不希望EXPECT_TRUE(service.registerCallback(SessionCallback_t));编译,因为SessionCallback_t命名的是一个类型,而不是一个类型的实例,所以你不能传入它。再说一遍,你想实现什么?


更新到注释:

Mocking需要虚拟函数(或鸭子类型(和依赖项注入。

如果您只想测试registerCallback(),我怀疑您根本不需要mock。相反,您需要查看函数的文档,看看它说它将做什么——有时称为契约。例如,函数的先决条件和后决条件是什么?它可能会遇到哪些错误情况?这些是单元测试应该涵盖的内容。

例如,它是否只保留一个回调(提示:如所写,是的(?当已经注册了回调时调用它会发生什么?它是否允许传入默认初始化的std::function对象?

更大的问题是,你如何验证你的测试是正确的。如果你开始在回调中触发通知,你就超出了孤立测试这个函数的范围。相反,您可以在测试中创建一个访问器类来公开什么是私有的,以便进行验证。尽管如此,您无法比较std::function的相等性,所以您能做的最好的事情就是调用它并检查是否发生了预期的副作用:

class TestService : public Service {
public:
const SessionCallback_t& getCallback() const { return mCallback; }
};
struct TestCallback
{
int mCount = 0;
void operator()( const Session& ) { ++mCount; }
};

然后在你的测试中,你可以写一个测试,比如:

TEST_F(MyTestService , Test_registerCallback_BadCallback) {
auto service = TestService{};
EXPECT_THROW( service.registerCallback( SessionCallback_t{} ), std::out_of_range );
}   
// Register and check that it's our callback
TEST_F(MyTestService , Test_registerCallback_CallbackSaved) {
auto service  = TestService{};
auto callback = TestCallback{};
EXPECT_TRUE( service.registerCallback( callback ) );
EXPECT_EQ( callback.mCount, 0 );
auto actualCallback = service.getCallback();
EXPECT_TRUE( actualCallback );
actualCallback();
EXPECT_EQ( callback.mCount, 1 );
}   
TEST_F(MyTestService , Test_registerCallback_CallbackOverwrite) {
auto service   = TestService{};
auto callback1 = TestCallback{};
auto callback2 = TestCallback{};
EXPECT_TRUE( service.registerCallback( callback1 ) );
EXPECT_TRUE( service.registerCallback( callback2 ) );
EXPECT_EQ( callback1.mCount, 0 );
EXPECT_EQ( callback2.mCount, 0 );
auto actualCallback = service.getCallback();
EXPECT_TRUE( actualCallback );
actualCallback();
EXPECT_EQ( callback1.mCount, 0 );
EXPECT_EQ( callback2.mCount, 1 );
}   

最新更新