我正在测试一些大量使用回调的代码,它看起来像这样:
class Client {
public:
Client(Socket socket) {
socket->onA([this] {
// call private Client methods....
});
socket->onB([this] {
// call private Client methods...
});
// repeated for onC, onD, and onE
}
void Start();
void Stop();
private:
// and almost all of the state is private
};
几乎完全通过Socket
提供的界面与外界进行通信,如下所示:
class Socket {
public:
void onA(std::function<void()> callBack) = 0;
void onB(std::function<void()> callBack) = 0;
void onC(std::function<void()> callBack) = 0;
void onD(std::function<void()> callBack) = 0;
void onE(std::function<void()> callBack) = 0;
// various other public methods
};
重要的是,我既可以验证已调用onX
函数,也可以访问传递给它们的参数(因为Client
&#39; s状态变化响应来自Socket
的通知,我需要模拟我的测试中的那些。
我可以写一个看起来像的模拟:
class MockSocket : public Socket {
public:
MOCK_METHOD1(onA, void(std::function<void()> callBack));
MOCK_METHOD1(onB, void(std::function<void()> callBack));
// etc
};
但是我需要能够写出对表单的期望:&#34;期望这个MockSocket
对象调用一次onA
方法,现在调用作为参数传递的函数到onA
。现在检查是否使用此字符串调用了write
Socket
方法:....&#34;
在另一种情况下,当我只有这种功能时,我做了类似的事情:
class MockSocket : public Socket {
public:
// as before
void setCallbackForA(std::function<void()> callBack) {
callbackForA = callBack;
}
void callCallbackForA() {
callbackForA();
}
// etc
private:
std::function<void()> callbackForA;
std::function<void()> callbackForB;
// etc
};
但是要完成这项工作将会是一个荒谬的样板(5个getter和5个setter +所有EXPECT_CALL
s,这将从测试用例到testcase),而我怀疑必须有更好的方法来做到这一点(不使用C风格的宏)。有一些模板魔法可以帮助吗?有什么可以让它更容易处理?
答案 0 :(得分:2)
我假设您正在测试Client
类 - 所以您真正需要的是存储Client
在Socket
中注册的回调函数。通过SaveArg<N>
操作执行此操作。见代码:
class ClientTest : public ::testing::Test
{
public:
std::function<void()> onACallback;
std::function<void()> onBCallback;
//...
MockSocket mockSocket;
std::unique_ptr<Client> objectUnderTest;
void SetUp() override
{
using ::testing::SaveArg;
EXPECT_CALL(mockSocket, onA(_)).WillOnce(SaveArg<0>(&onACallback));
EXPECT_CALL(mockSocket, onB(_)).WillOnce(SaveArg<0>(&onBCallback));
//...
objectUnderTest = std::make_unique<Client>(mockSocket);
}
};
使用上面的Test类 - 您可以收集所有回调。您可以使用这些捕获的回调来触发Client类中的操作,如下面的测试用例:
TEST_F(ClientTest, shallDoThisAndThatOnA)
{
// here you put some expectations
//...
onACallback(); // here you trigger your Client object under test
// now you make some assertions (post actions)
//...
}