用于单元测试的模式,用于进行标准库调用的C ++方法 [英] Patterns for unit testing a C++ method that makes a standard library call

查看:98
本文介绍了用于单元测试的模式,用于进行标准库调用的C ++方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在写一个C ++类来封装套接字(我知道有很好的库 - 我自己滚动练习):

  class Socket {
public:
int init(void); //调用套接字(2)
//其他我们不关心的代码示例
};

这个类又被其他几个使用,我知道我可以使用 googlemock



但我希望开发此类首先测试,目前有点卡住。我不能使用googlemock上的C标准库(即 socket.h ,在这种情况下),因为一个C ++类,它不是。我可以在需要的C标准库函数的基础上创建一个简单的C ++包装类,例如

  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 ++开发的标准模式?

解决方案

可能通过工作通过套接字接口(即基类)和实现该基类的测试版本。



您可以通过几种方法来实现这一点,例如最简单的方法是使用C ++接口指定整个套接字API。

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

然后提供一个通过BSD套接字库工作的具体实现



class CBsdSocketLib:public ISocket
{
public:
// yadda,同样的东西,但实际上调用BSD套接字接口
};


class CTestSocketLib:public ISocket
{
public:
//模拟套接字库
};

通过对接口进行编码,您可以创建测试版本,

但是,我们可以清楚地看到,这第一遍是相当奇怪。我们包装了一个整个库,它不是一个真正的类,它描述对象的意义上。



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

  //负责套接字创建/构造
class ISocketFactory
{
virtual ISocket * createSocket(...)= 0; // perform socket()and maybe bind()
};

//一个socket
类ISocket
{
//纯虚拟recv,发送,监听,关闭等
};

现场使用:

  class CBsdSocketFactory:public ISocketFactory 
{
...
};

class CBsdSocket:public ISocket
{
...
};

测试:

  class CTestSocketFactory:public ISocketFactory 
{
};

class CTestSocket:public ISocket
{
};

并将BSD库调用分成那些有自己职责的两个不同的类。


I'm writing a C++ class to wrap sockets (I know that there are good libraries for this--I'm rolling my own for practise):

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

This class is in turn used by several others, which I know I can unit test with googlemock by subclassing and mocking.

But I would like to develop this class test first, and am a bit stuck currently. I can't use googlemock on the C standard library (i.e. socket.h, in this case), since a C++ class it is not. I could create a thin C++ wrapper class around the C standard library functions I need, e.g.

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);
};

Now I can mock that and unit test my Socket class (which might now need to be renamed Network or some such). LibcWrapper could come in handy for other classes as well, and would not itself need to be unit tested since it just provides a bunch of class methods.

This is starting to sound good to me. Have I answered my own question, or do there exist standard patterns for test driving this sort of development in C++?

解决方案

I would probably mock it by working through a socket interface (ie base class) and implementing a test version of that base class.

You can do this a couple of ways, for example the simplest thing is to specify the entire socket API in terms of a C++ interface.

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

Then provide a concrete implementation that worked through the BSD sockets library

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


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

By coding against the interface you can create your test version to do whatever you like.

However, we can clearly see that this first pass is rather weird. We're wrapping an entire library, its not really a class in the sense that it describes objects.

You'd rather think in terms of sockets and ways to manufacture sockets. This would be more object oriented. Along those lines I'd separate the functionality above into two classes.

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

For live use:

   class CBsdSocketFactory : public ISocketFactory
   {
      ...
   };

   class CBsdSocket : public ISocket
   { 
      ...
   };

For testing:

   class CTestSocketFactory : public ISocketFactory
   {
   };

   class CTestSocket : public ISocket
   {
   };

And separate the BSD library calls into those two distinct classes that have their own responsibilities.

这篇关于用于单元测试的模式,用于进行标准库调用的C ++方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆