2011-04-25 5 views
10

소켓을 랩핑하기 위해 C++ 클래스를 작성하고 있습니다. (연습용으로 좋은 라이브러리가 있다는 것을 알고 있습니다.)표준 라이브러리 호출을하는 C++ 메소드를 테스트하는 패턴

class Socket { 
public: 
    int init(void); // calls socket(2) 
    // other stuff we don't care about for the sake of this code sample 
}; 

이 클래스는 차례대로 서브 클래스 화 및 조롱을 통해 googlemock으로 단위 테스트를 할 수 있다는 것을 알고 있습니다.

그러나이 클래스는 test first으로 개발하고 싶습니다. 현재 조금 갇혀 있습니다. C++ 클래스이므로 googlemock을 C 표준 라이브러리 (즉, socket.h)에 사용할 수 없습니다. I 은 C 표준 라이브러리 함수를 중심으로 얇은 C++ 래퍼 클래스를 만들 수 있습니다.

class LibcWrapper { 
public: 
    static int socket(int domain, int type, int protocol); 
    static int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 
    static int listen(int sockfd, int backlog); 
    static int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 
    static ssize_t write(int fd, const void *buf, size_t count); 
    static int close(int fd); 
}; 

지금은 그 조롱 수 있으며, 단위는 (지금 Network 이름을 변경하거나 일부 등해야 할 수도 있습니다) 내 Socket 클래스를 테스트합니다. LibcWrapper은 다른 클래스에도 도움이 될 수 있으며 클래스 테스트 방법을 제공하기 때문에 단위 테스트를 수행하지 않아도됩니다.

이것은 나에게 좋게 들리기 시작했습니다. 내 자신의 질문에 대답 했습니까? 아니면 이런 종류의 개발을 C++로 테스트하는 표준 패턴이 있습니까?

+2

googlemock [요리 책] (http://code.google.com/p/googlemock/wiki/CookBook#Mocking_Free_Functions)은 당신과 비슷한 것을 제안합니다. – beduin

+0

@ 베두인 : 대답 해 주시면 투표 할게요. :) –

+0

@Josh Glover : done)) – beduin

답변

4

소켓 인터페이스 (예 : 기본 클래스)를 통해 작업하고 해당 기본 클래스의 테스트 버전을 구현하여 조롱합니다.

두 가지 방법이 있습니다. 예를 들어 가장 간단한 방법은 C++ 인터페이스 측면에서 전체 소켓 API를 지정하는 것입니다.

class ISocket 
    { 
    public: 
     virtual int socket(int domain, int type, int protocol) = 0; 
     virtual int bind(int sockfd...) = 0; 
     // listen, accept, write, etc    
    }; 

그런 다음 당신은 당신이 원하는대로 할 테스트 버전을 만들 수있는 인터페이스에 대해 코딩함으로써 BSD 소켓 라이브러리

class CBsdSocketLib : public ISocket 
    { 
    public: 
     // yadda, same stuff but actually call the BSD socket interface 
    }; 


    class CTestSocketLib : public ISocket 
    { 
    public: 
     // simulate the socket library 
    }; 

을 통해 일 구체적인 구현을 제공합니다.

그러나이 첫 번째 패스가 다소 이상하다는 것을 분명히 알 수 있습니다. 우리는 전체 라이브러리를 래핑하고 있습니다. 실제로 클래스는 객체를 설명한다는 의미가 아닙니다.

소켓 및 소켓 제조 방법에 대해 생각해보십시오. 이것은 객체 지향적 일 것입니다. 그 선상에서 나는 위의 기능을 두 개의 클래스로 분리했다. 테스트를 위해

class CBsdSocketFactory : public ISocketFactory 
    { 
     ... 
    }; 

    class CBsdSocket : public ISocket 
    { 
     ... 
    }; 

:

// responsible for socket creation/construction 
    class ISocketFactory 
    { 
     virtual ISocket* createSocket(...) = 0; // perform socket() and maybe bind() 
    }; 

    // a socket 
    class ISocket 
    { 
     // pure virtual recv, send, listen, close, etc 
    }; 
라이브 사용하기 위해

class CTestSocketFactory : public ISocketFactory 
    { 
    }; 

    class CTestSocket : public ISocket 
    { 
    }; 

을 그리고 자신의 책임이 그 두 가지 클래스로 BSD 라이브러리 호출을 구분합니다.

+0

나는이 접근 방식이 상당히 마음에 든다. 감사! –

2

나는 그 기술도 사용했습니다. Google Mock은 정적 함수 조롱을 지원하지 않습니다. The FAQ explains that you should use an interface은 일반적인 Google Mock 방식으로 재정의 할 수있는 가상 메소드가 있습니다.

+0

감사! Doug T의 사례는 그가 제공 한 모든 세부적인 내용만으로 받아 들였지만 googlemock FAQ 링크에 대한 투표는 확실합니다. :) –

1

Google Mock cookbook은 귀하의 사례에서 비슷한 것을 제안합니다.

관련 문제