我开始在某些C / C ++项目中使用CppUTest。特别是嘲弄扩展声音很好,但我目前正在努力如何以正确的方式设置模拟。假设用于抽象网络套接字通信的低级类。
我的第一种方法:
size_t CMockSocket::recv(void* buf, size_t len) { return (size_t) mock().actualCall("recv") .withParameter("len", (int) len) .returnValue().getIntValue(); }
设定期望:
mock().expectOneCall("recv") .withParameter("len", 20) .andReturnValue(15);
到目前为止一切顺利。但我需要的是提供更多数据 - 在这种情况下,我希望通过buf指针返回15个字节。我尝试使用.setData()
和setDataObject()
方法。但看起来这些函数将数据存储在命名变量中,而不是预期的函数调用。因此,后续调用将覆盖前面的数据,对吗?
我目前的问题是如何将其他返回数据传递给模拟方法?我的第一个方法是创建一个包含返回值(size_t)和数据缓冲区的结果类。像这样:
class CRecvResults { public: size_t m_returnValue; void* m_buffer; CRecvResults(size_t returnValue, void* buffer) : m_returnValue(returnValue), m_buffer(buffer) {} ~CRecvResults() {} }; size_t CMockSocket::recv(void* buf, size_t len) { CRecvResults* pResults = (CRecvResults*) mock().actualCall("recv") .withParameter("len", (int) len) .returnValue().getPointerValue()); assert(pResults != NULL); assert(buf != NULL); assert(len >= pResults->m_buffer.length()); memcpy(buf, pResults->m_buffer.data(), pResults->m_buffer.length()); return pResults->m_returnValue; }
期待:
char* buffer = "some returning buffer content at least 15 chars long"; CRecvResults results(15, buffer); mock().expectOneCall("recv") .withParameter("len", 20) .andReturnValue(&results);
问题:这是正确的方式还是我错过了什么?我需要缓冲区内容,因为我需要测试结果解释器。
我的第二种方法:
bool CMockSocket::send(const void* buf, size_t len) { return mock().actualCall("send") .withParameter("len", (int) len) .returnValue().getIntValue(); }
设定期望:
mock().expectOneCall("send") .withParameter("len", 20) .andReturnValue(true);
在这种情况下,我想验证由测试代码生成的buf中的传出数据。因此,我需要将缓冲区内容(和长度)返回给测试函数。像这样:
class CSendResults { public: bool m_returnValue; char* m_buffer; size_t m_length; CSendResults(bool returnValue, char* buffer, size_t length) : m_returnValue(returnValue), m_buffer(buffer), m_length(length) {} ~CSendResults() {} }; bool CMockSocket::send(const void* buf, size_t len) { CSendResults* pResults = (CSendResults*) mock().actualCall("send") .returnValue().getPointerValue(); assert(pResults != NULL); assert(buf != NULL); assert(pResults->m_length >= len); memcpy(pResults->m_buffer, buf, len); pResults->m_length = len; return pResults->m_returnValue; }
期待:
char buffer[1024]; CSendResults results(true, buffer, sizeof(buffer); mock().expectOneCall("send") .withParameter("len", 20) .andReturnValue(&results); // further checks for results content...
这看起来非常丑陋,对我来说有很多开销。我的问题再一次:这是正确的方式还是我错过了什么?
我的最后一个问题:难道我正在测试完全错误的方式吗?请告诉我您的经历和做法!
答案 0 :(得分:2)
CppUTest中添加了一项新功能,可让您为模拟指定输出参数。这就是它的样子:
{
return (size_t) mock().actualCall("recv")
.withOutputParameter("buf", buf)
.withParameter("len", (int) len)
.returnUnsignedLongIntValueOrDefault(0);
}
期望可能如下所示:
char buffer[] = "blabla";
mock().expectOneCall("recv")
.withOutputParameterReturning("buf", buffer, sizeof(buffer))
.withParameter("len", sizeof(buffer))
.andReturnValue(sizeof(buffer));
buffer
的内容将通过输出参数复制到模拟的调用者。因此,不再需要丑陋的解决方法。
答案 1 :(得分:0)
我正在使用以下丑陋的解决方法。 我为返回值定义了一个结构类型,加上我在假函数中需要的附加数据。 我分配并填充一个实例,我调用expectOneCall()并使用“.andReturnValue()”传递它。在伪函数中,我使用“... returnValue()。getPointerValue()”得到我的数据,然后我将返回值设置为struct-> rc,并处理我的附加数据(将其复制/比较到缓冲区)。在退出假函数之前,结构被释放。
这样,所需的附加数据被绑定到函数调用的参数列表中。
Foltos