2017-01-19 1 views
1

BSD 소켓을 사용하여 우분투에 서버/클라이언트 기반 C++ 응용 프로그램을 작성했습니다. 내 단위 테스트 프레임 워크로 Google C++ Test Framework를 사용하고 있습니다.BSD 소켓을 테스트하는 방법

내 단위 테스트에서 서버와 클라이언트를 만들 수있는 방법이 있는지 궁금하므로 서버를 청취/수락하고 양측 모두를 보내고받을 수 있습니다.

질문 : 서버에 대해 소켓 수락을 테스트 한 후이 테스트에서 클라이언트에 연결할 수있는 방법은 무엇입니까? 다중 스레딩을 사용하여 동일한 TEST() (또는 TEST_F()) 범위에서 테스트중인 서버에 클라이언트를 연결할 수 있습니까?

필자는 클라이언트를 작성하고 테스트중인 서버에 수동으로 연결할 수 있지만 자동 단위 테스트의 목적을 무효화합니다.

Google 모크에 대한 내용을 읽었을 때 나를 위생 검사 (어떤 기능이 호출되는지, 몇 번이나 돌아 왔는지 등을 확인하는 것)가되었습니다.

감사합니다.

+1

소켓에 대한 추상화를 생성하여 클래스에 삽입합니다. 그럼 너는 그것을 조롱 할 수있다. –

+0

@BartoszPrzybylski 몇 가지 예를 보여 주시겠습니까? 나는 개발 된 개발을 시험하기에 새롭고 어떻게 주사를 할 수 있는지 잘 모릅니다. 고마워. – Joe

+0

TCP 연결을 나타내는 추상 기본 클래스를 작성하고 데이터 읽기/쓰기 등의 메소드를 가지고 있습니다. 그런 다음 프로덕션 코드는 실제 소켓을 사용하여 논리를 구현하는 클래스를 파생시킬 수 있으며 테스트 단위는 논리를 구현하는 다른 클래스를 파생시킬 수 있습니다 가짜 데이터를 사용합니다. 모든 기본 클래스 인터페이스를 사용하여 나머지 유닛 코드를 작성한 다음 필요할 때 적절한 파생 클래스를 인스턴스화 할 수 있습니다. 이렇게하면 실제 네트워크 동작을 테스트하지 않는 한 테스트 중에 실제 소켓을 사용할 필요가 없습니다. –

답변

1

좋아, 네트워크 소켓에 대한 추상화를 만드는 것으로 시작하자. 호출을 시스템 기능으로 조롱 할 수 있어야합니다. 이 같은 시작 :

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 */ 
} 

위의 코드는 sockaddrsocklen_t을 사용하고 있기 때문에, 물건과 유닉스 클래스의 결합이 아닌 추상적 많이한다. 또한 두 가지 유형의 플랫폼에 독립적 인 코드를 사용하기 위해 추상화를 작성해야하지만 이는 설계에 따라 다릅니다.

실제 응용 프로그램에서 사용하기 위해 구체적인 TCP/UDP 클래스를 만들 필요는 없습니다.

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 :) 수업에 착수합시다.

클래스 이름이 A이며 method 테스트 방법이 있다고 가정합니다. 클래스에서 생성자로 Socket*을 가져 오거나 methodSocket*을 매개 변수로 사용해야합니다. 그런 다음 테스트 코드에서 모의를 지정할 수 있습니다.

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

는 단지 MockSock 인스턴스화 적절한 EXPECT_CALLA 또는 method로 전달한다.

+0

답장을 보내 주셔서 대단히 감사 합니다만, 수락을 요청할 때 클라이언트에 연결해야합니다. 그렇지 않으면 제한 시간이 없거나 클라이언트가 연결되면 테스트가 거부됩니다. 단위 테스트를 사용하여 어떻게 달성 할 수 있습니까? – Joe

+0

@Joe 소켓에 연결하기 위해 클라이언트가 필요하지 않습니다.그게 전부 조롱의 요지 야. GMock은 당신이 할 일을 지시 할 것이며, 그렇게하도록 지시 할 필요가 있습니다. 이것이 시스템 기능을 호출하지 않기 위해 추상화가 도입 된 이유입니다. –

+0

그래서 실제 소켓 수락 함수를 테스트하지 않고이 서브 루틴 내부의 다른 로직 (수락에 추가 한 경우)과 시스템 동작 (예 :이 함수가 필요할 때 호출되는지 여부 등) – Joe