How to stub a socket in C?

Viewed 2798

I've written client code that's supposed to send some data through a socket and read back an answer from the remote server.

I would like to unit-test that code. The function's signature is something along the lines of:

double call_remote(double[] args, int fd);

where fd is the file descriptor of the socket to the remote server.

Now the call_remote function will, after sending the data, block on reading the answer from the server. How can I stub such a remote server for unit-testing the code?

Ideally I would like something like:

int main() {
  int stub = /* initialize stub */
  double expected = 42.0;

  assert(expected == call_remote(/* args */, stub);

  return 0;
}

double stub_behavior(double[] args) {
  return 42.0;
}

I would like stub_behavior to be called and send the 42.0 value down the stubbed file descriptor.

Any easy way I can do that?

4 Answers

Here is a C++ implementation (I know, the original question was for C, but it is easy to convert back to C if desired). It probably doesn't work for very large strings, as the socket will probably block if the string can't be buffered. But it works for small unit tests.

/// Class creates a simple socket for testing out functions that write to a socket.
/// Usage:
///  1. Call GetSocket() to get a file description socket ID
///  2. write to that socket FD
///  3. Call ReadAll() read back all the data that was written to that socket.
///  The sockets are all closed by ReadAll(), so this is a one-use object.
///
/// \example
///  MockSocket ms;
///  int socket = ms.GetSocket();
///  send(socket,"foo bar",7);
///  ...
///  std::string s = ms.ReadAll();
///  EXPECT_EQ("foo bar",s);

class MockSocket
{
public:
    ~MockSocket()
    {
    }


    int GetSocket()
    {
        socketpair(AF_UNIX, SOCK_STREAM, 0, sockets_);
        return sockets_[0];
    }

    std::string ReadAll()
    {
        close(sockets_[0]);
        std::string s;
        char buffer[256];
        while (true)
        {
            int n = read(sockets_[1], buffer, sizeof(buffer));
            if (n > 0) s.append(buffer,n);
            if (n <= 0) break;
        }
        close(sockets_[1]);
        return s;
    }
private:
    int sockets_[2];
};
Related