How to unit test BSD sockets [closed]

空扰寡人 提交于 2020-01-01 11:53:06

问题


I am writing a server/client based C++ application in Ubuntu with BSD socket. I am using Google C++ Test Framework as my unit test framework.

I wonder is there a way that I can create a server and client in my unit test, so I can test listen/accept for the server, and send/receive for both sides.

The question is, if I am going to test socket accept (after listening to a port) for the server, how can I have some client connecting to it in this test? Can I use multi-threading to have a client connect to the server being tested in the same TEST() (or TEST_F()) scope?

I can write a client and manually connect to the server under test for sure, but it defeat the purpose of automated unit test.

I read something about the Google Mock, it looks more like a sanity check for me (seeing which functions are being called, how many times, what got returned, etc.).

Please help, thanks.


回答1:


Ok, lets start with creating abstraction for network socket. We need this to be able to mock the calls to system functions. Start with something like this:

class Socket {
public:
    virtual bool connect(const struct sockaddr *address, socklen_t address_len) = 0;
    virtual Socket* accept(struct sockaddr *restrict address, socklen_t *restrict address_len) = 0;
    /* more functions */
}

The above code doesn't abstract a lot of stuff and its bind to unix classes, because it is using sockaddr and socklen_t. You should also create abstraction for those two types to have platform independent code, but this depends on your design.

Not you need to create a concrete TCP/UDP class for using it in real application.

class TCPSocket : public Socket { 
public:
    TCPSocket() {
        socket_ = socket(PF_INET, SOCK_STREAM, 0);
        if (socket_ == -1) {
            /* handle errors */
        } 
    }
    TCPSocket(int sock) : socket_(sock) {}
    bool connect(const struct sockaddr *address, socklen_t address_len) override {
        return connect(socket_, address, address_len) == 0;
    }
    Socket* accept(struct sockaddr *restrict address, socklen_t *restrict address_len) override {
        int s = accept(socket_, address, address_len);
        if (s == -1) {
            /* handle errors */
        }
        return new TCPSocket(s);
    }
private:
    int socket_;
} 

Phew :) let's move on to your class.

Lets assume your class is named A and has method for testing method. Your class should either take Socket* in constructor, or method should take Socket* as a parameter. Then in your testing code you can specify a mock.

class MockSock : public Socket {
public:        
    MOCK_METHOD2(connect, bool(const struct sockaddr*, socklen_t));
    MOCK_METHOD2(accept, Socket*(struct sockaddr*, socklen_t*));
}

then just instantiate MockSock and pass it to A or method with proper EXPECT_CALL values.



来源:https://stackoverflow.com/questions/41753538/how-to-unit-test-bsd-sockets

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!