I am trying to write unit tests for a socket app. I am using the <sys/socket.h>
header. In order to test a method, I should mock the socket free functions, so the method is tested in isolation from its dependencies. Here is my attempt, following this instructions:
Test file:
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "path/to/ClientConectionHeader"
#include <sys/socket.h>
using ::testing::AtLeast;
class EstablishSocketInterface {
public:
virtual int establishSock(int domain, int type, int protocol) = 0;
};
class EstablishSocket : public EstablishSocketInterface {
public:
int establishSock(int domain, int type, int protocol) override {
return socket(domain, type, protocol);
}
};
class MockSocket : public EstablishSocket {
public:
MOCK_METHOD(int, establishSock, (int domain, int type, int protocol));
};
TEST(ClientConnection, ClientConnectionConstructor) {
MockSocket mockSocket;
EXPECT_CALL(mockSocket, establishSock(AF_INET, SOCK_STREAM, 0))
.Times(AtLeast(1));
std::string serverIp="127.0.0.1";
int port=49151;
ClientConnection client(serverIp,port);
}
Header of the class I am testing:
#pragma once
class ClientConnection
{
public:
ClientConnection(std::string& serverIp_input,int port_input);
private:
int socketfd;
const char* serverIp;
int port;
bool ExitProgram;
};
Constructor definition:
ClientConnection::ClientConnection(std::string& serverIp_input, int port_input) {
this->socketfd=socket(AF_INET, SOCK_STREAM, 0);
if (this->socketfd < 0) {
perror("socket");
}
this->serverIp = serverIp_input.c_str();
this->port = port_input;
this->ExitProgram = false;
}
The test fails with the following: Failure
Actual function call count doesn't match EXPECT_CALL(mockSocket, establishSock(2, SOCK_STREAM, 0))...
Expected: to be called at least once
Actual: never called - unsatisfied and active
[ FAILED ] ClienConection.ClientConectionConstructor (0 ms)
The constructor calls the socket() function itself, does not use the mocked one. Dependency injection can work but requires changing the original code. I don't think this is the right approach. Also, to use EXPECT_EQ()
to check whether the fields are valued the same as the arguments I pass to the constructor, I need getters, which also requires to be added, but are not needed in the 'production' code.
So how do I gtest my methods as I mock the socket()
, send()
, recv()
, close()
functions from the <sys/socket.h>
header?
Thanks in advance!
EstablishSocketInterface
is never used in the scope of ClientConnection
so establishSock
is never called (no matter if we consider EstablishSocket
or MockSocket
. You need to use some form of the technique called 'dependency injection' (e.g. see Dependency injection with unique_ptr to mock). You'll need to wrap all methods (like socket(), send(), recv(), close()
) in an interface and use this interface everywhere where you would normally used sys/socket.h
directly.
There's also another technique - the one mentioned in the original question. It requires that all your code is templated so it's not that easy to use. If you insist on it though, then ClientConnection
would need to be a templated class with socket
as template parameter.