单元测试用于进行标准库调用的C ++方法的模式

时间:2011-04-25 14:54:34

标签: c++ unit-testing

我正在编写一个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(在这种情况下是socket.h),因为它不是C ++类。我可以创建一个围绕我需要的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);
};

现在我可以模拟那个并单元测试我的Socket类(现在可能需要重命名为Network或其他类)。 LibcWrapper也可以为其他类派上用场,并且本身不需要进行单元测试,因为它只提供了一堆类方法。

这对我来说开始听起来不错。我是否回答了自己的问题,或者是否存在用于在C ++中进行此类开发的测试的标准模式?

3 个答案:

答案 0 :(得分: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
   };

通过对界面进行编码,您可以创建测试版本以执行任何操作。

然而,我们可以清楚地看到这第一次传球相当奇怪。我们正在包装整个库,它不是真正的类,因为它描述了对象。

你宁愿考虑插座和制造插座的方法。这将更加面向对象。沿着这些方向,我将上面的功能分成两个类。

   // 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 CBsdSocketFactory : public ISocketFactory
   {
      ...
   };

   class CBsdSocket : public ISocket
   { 
      ...
   };

进行测试:

   class CTestSocketFactory : public ISocketFactory
   {
   };

   class CTestSocket : public ISocket
   {
   };

将BSD库调用分成两个有不同职责的不同类。

答案 1 :(得分:2)

我也使用过那种技术。请注意,Google Mock并不完全支持模拟静态函数。 The FAQ explains that you should use an interface使用虚拟方法,您可以采用通常的Google Mock方式覆盖。

答案 2 :(得分:1)

Google Mock cookbook在您的案例中提出类似的建议。