3

I'm starting using CppUTest for some C/C++ projects. Especially the mocking extension sound good, but I'm currently struggling how to set up mocks in the right way. Assume a low level class for abstracting network socket communication.

My first method:

size_t CMockSocket::recv(void* buf, size_t len)
{
  return (size_t) mock().actualCall("recv")
      .withParameter("len", (int) len)
      .returnValue().getIntValue();
}

Setting up the expectation:

mock().expectOneCall("recv")
    .withParameter("len", 20)
    .andReturnValue(15);

So far so good. But what I would need is to give more data - in this case the 15 bytes I want to give back via buf pointer. I tried to use the .setData() and setDataObject() methods. But it looks like that functions stores the data in named variables, not with the expected function call. Therefore subsequent calls will override the preceding data, right?

My current problem is how can I pass additional returning data to the mocking method? My first aproach for this was to create a resulting class which contains both the return value (size_t) and the data buffer. Like this:

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;
}

And the expectation:

char* buffer = "some returning buffer content at least 15 chars long";
CRecvResults results(15, buffer);
mock().expectOneCall("recv")
      .withParameter("len", 20)
      .andReturnValue(&results);

Question: is this the right way or do I miss something? I need the buffer content because i need to test the result interpreter.

My second method:

bool CMockSocket::send(const void* buf, size_t len)
{
  return mock().actualCall("send")
      .withParameter("len", (int) len)
      .returnValue().getIntValue();
}

Setting up the expectation:

mock().expectOneCall("send")
    .withParameter("len", 20)
    .andReturnValue(true);

In this case I want to verify the outgoing data in buf, generated by the code under test. Therefore I need to return that buffer content (and length) to the test function. Like this:

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;
}

And the expectation:

char buffer[1024];
CSendResults results(true, buffer, sizeof(buffer);
mock().expectOneCall("send")
      .withParameter("len", 20)
      .andReturnValue(&results);

// further checks for results content...

This looks very ugly and with a lot of overhead to me. Again my question: is this the right way or do I miss something?

And my final question: can it be that I'm testing the completely wrong way? Please let me know about your experiences and practices!

2 Answers 2

3

A new feature has been added to CppUTest, which lets you specify an output parameter for mocks. This is what it might look like:

{
    return (size_t) mock().actualCall("recv")
        .withOutputParameter("buf", buf)
        .withParameter("len", (int) len)
        .returnUnsignedLongIntValueOrDefault(0);
}

And the expectation might be specified like this:

char buffer[] = "blabla";

mock().expectOneCall("recv")
    .withOutputParameterReturning("buf", buffer, sizeof(buffer))
    .withParameter("len", sizeof(buffer))
    .andReturnValue(sizeof(buffer));

The contents of buffer will be copied to the caller of the mock via the output parameter. So the ugly workaround is no longer needed.

5
  • Thats good news! I will check it soon, look like a clean solution.
    – Andi
    Commented Apr 29, 2015 at 12:17
  • BTW, in which version is this feature added?
    – Andi
    Commented Apr 29, 2015 at 12:18
  • It is present in version 3.6. There have been a whole lot of improvements since then, so it might be worth looking at the current head.
    – A.Robert
    Commented Apr 29, 2015 at 13:42
  • Version 3.7 was released
    – A.Robert
    Commented May 1, 2015 at 5:58
  • Great! I was waiting for this for a long time. I have to read the documentation to see all the new stuff.
    – Andi
    Commented May 2, 2015 at 13:34
0

I am using the following ugly workaround. I define a structure type for the return value plus the additional data I need in my fake function. I allocate and fill one instance where I call expectOneCall() and pass it using ".andReturnValue()". In the fake function I get my data with "...returnValue().getPointerValue()", then I set the return value to struct->rc, and process my additional data (copy/compare it to buffer). Before exiting the fake function the structure is freed.

This way the additional data needed is bound to the parameter list of the function call.

Foltos

1
  • Thanks Foltos for your comment. I see we have similar approaches using a customized structure/object. With more experiences from the last month's I got the impression that this scenario will not come up very often. I tried to see how other xUnit frameworks handle this issue, but I didn't find any more general solutions.
    – Andi
    Commented Jul 13, 2013 at 9:18

Not the answer you're looking for? Browse other questions tagged or ask your own question.