如何起订量在一单元测试的NetworkStream? [英] How to moq a NetworkStream in a unit test?

查看:158
本文介绍了如何起订量在一单元测试的NetworkStream?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用起订量和放大器; 。NUnit的一个单元测试框架。



我已经写了被赋予的NetworkStream对象作为参数的方法:

 公共静态无效ReadDataIntoBuffer(的NetworkStream的NetworkStream,队列的DataBuffer)
{
如果((的NetworkStream = NULL)及!&安培;!(设置DataBuffer = NULL) )
{
,而(networkStream.DataAvailable)
{
字节[] = tempBuffer新的字节[512];

//读取从网络流的数据到临时缓冲器
的Int32 numberOfBytesRead = networkStream.Read(tempBuffer,0,512);

//所有数据移动到主缓冲区
为(我的Int32 = 0; I< numberOfBytesRead;我++)
{
dataBuffer.Enqueue(tempBuffer [一世]);
}
}
}
,否则
{
如果(的NetworkStream!= NULL)
{
抛出新的ArgumentNullException(的NetworkStream);
}

如果(!=的DataBuffer NULL)
{
抛出新的ArgumentNullException(设置DataBuffer);
}
}
}

现在我在看重新 - 写入我的单元测试此方法,因为先前笔试依靠真正的NetworkStream对象,不是非常好的处理。



我怎么能嘲笑的NetworkStream?我使用的起订量为事前提及。是否有可能呢?如果不是我怎么能解决这个问题呢?



期待您的反馈!



下面是
以前的解决方案:

 公共静态无效ReadDataIntoBuffer(流数据流,队列的DataBuffer)
{
如果((的NetworkStream = NULL)及!&安培;!(设置DataBuffer = NULL))
{
字节[] = tempBuffer新的字节[512];
的Int32 numberOfBytesRead = 0;

//读取从网络流的数据到临时缓冲器
而((numberOfBytesRead = dataStream.Read(tempBuffer,0,512)大于0)
{
//所有数据移动到主缓冲区
为(我的Int32 = 0; I< numberOfBytesRead;我++)
{
dataBuffer.Enqueue(tempBuffer [I]);
}
}
}
,否则...
}

更新:



我已经重写我的班再次使用以前的解决方案单元测试了罚款,但现实世界中的应用实例表明我,为什么它是不可能对我来说,用传递对象变成我的方法的(否则大)的建议。



首先,我的应用程序依赖于一个恒定的TCP连接。如果你使用 Stream.Read (这是可能的),也没有数据接收它会阻止执行。如果你指定一个超时如果没有接收到数据的异常将被抛出。这种行为是不是为(很简单)的应用程序,我需要接受的。我只是需要一个没有多余的装饰,定TCP连接。因此具有 NetworkStream.DataAvailable 属性是极为重要的我的执行



与目前的解决方案:



我最后写一个接口和一个包装的NetworkStream。我也结束了传递字节数组临时接收缓冲区到方法。单元测试现在它工作得很好。

 公共静态无效ReadDataIntoBuffer(INetworkStream的NetworkStream,队列的DataBuffer,字节[] tempRXBuffer)
{
如果((的NetworkStream = NULL)及!及(设置DataBuffer = NULL)及!&安培;!(tempRXBuffer = NULL))
{
//读取数据从网络流进临时缓冲区
,而(networkStream.DataAvailable)
{
的Int32 numberOfBytesRead = networkStream.Read(tempRXBuffer,0,tempRXBuffer.Length);

//所有数据移动到主缓冲区
为(我的Int32 = 0; I< numberOfBytesRead;我++)
{
dataBuffer.Enqueue(tempRXBuffer [一世]);
}
}
}
,否则...
}

这是我使用的单元测试:

 公共无效TestReadDataIntoBuffer()
{
变种networkStreamMock =新的模拟< INetworkStream>();
StringBuilder的SB =新的StringBuilder();

sb.Append(_testMessageConstant1);
sb.Append(_testMessageConstant2);
sb.Append(_testMessageConstant3);
sb.Append(_testMessageConstant4);
sb.Append(_testMessageConstant5);


// ARRANGE
字节[] = tempRXBuffer Encoding.UTF8.GetBytes(sb.ToString());

//返回true,这样调用的Read()由
networkStreamMock.Setup(X => x.DataAvailable).Returns(真);

networkStreamMock.Setup(X => x.Read(It.IsAny&下;字节[]≥(),It.IsAny&所述; INT>(),It.IsAny&所述; INT>()) ).Callback(()=>
{
//后调用的Read()重新设置的属性,以便我们
//我们退出该数据读取循环再
networkStreamMock.Setup(X => x.DataAvailable).Returns(假);

})返回(tempRXBuffer.Length)。

的队列中resultQueue =新队列();

// ACT
ReadDataIntoBuffer(networkStreamMock.Object,resultQueue,tempRXBuffer);

// ASSERT
Assert.AreEqual(Encoding.UTF8.GetBytes(sb.ToString()),resultQueue.ToArray());
}


解决方案

您不能嘲笑的NetworkStream 带起订量,因为它不是一个抽象类或接口。但是,您可以创建在它之上的抽象,改变你的方法接受的是抽象的一个实例。这可能是这样的:

 公共接口IMyNetworkStream 
{
INT读([输入,输出]字节[]缓冲区,诠释抵消,诠释大小);
布尔DataAvailable {获得;}
}

现在你创建一个类,实现该接口:

 公共类MyNetworkStream:IMyNetworkStream 
{
私人的NetworkStream流;

公共MyNetworkStream(的NetworkStream NS)
{
如果(NS == NULL)抛出新的ArgumentNullException(NS);
this.stream = NS;
}

公共BOOL DataAvailable
{
得到
{
返回this.stream.DataAvailable;
}
}

公众诠释读取([输入,输出]字节[]缓冲区,诠释抵消,诠释大小)
{
返回这一点。 stream.Read(缓冲器,偏移,大小);
}

}

现在,你可以改变你的方法签名使用 IMyNetworkStream 的实例,并使用最小起订量来创建 IMyNetworkStream 的模拟。


I'm using Moq & NUnit as a unit test framework.

I've written a method that is given a NetworkStream object as a parameter:

public static void ReadDataIntoBuffer(NetworkStream networkStream, Queue dataBuffer)
{
  if ((networkStream != null) && (dataBuffer != null))
  {
     while (networkStream.DataAvailable)
     {
        byte[] tempBuffer = new byte[512];

        // read the data from the network stream into the temporary buffer
        Int32 numberOfBytesRead = networkStream.Read(tempBuffer, 0, 512);

        // move all data into the main buffer
        for (Int32 i = 0; i < numberOfBytesRead; i++)
        {
           dataBuffer.Enqueue(tempBuffer[i]);
        }
     }
  } 
  else
  {
     if (networkStream != null)
     {
        throw new ArgumentNullException("networkStream");
     }

     if (dataBuffer != null)
     {
        throw new ArgumentNullException("dataBuffer");
     }
  }
}

Now I am looking at re-writing my unit tests for this method since the previously written tests rely on real NetworkStream objects and are not very nice to handle.

How can I mock the NetworkStream? I'm using Moq as mentioned beforehand. Is it possible at all? If not how could I workaround this problem?

Looking forward to your feedback!

Here is the previous solution:

public static void ReadDataIntoBuffer(Stream dataStream, Queue dataBuffer)
{
  if ((networkStream != null) && (dataBuffer != null))
  {
     byte[] tempBuffer = new byte[512];
     Int32 numberOfBytesRead = 0;

     // read the data from the network stream into the temporary buffer
     while ((numberOfBytesRead = dataStream.Read(tempBuffer, 0, 512) > 0)
     {
        // move all data into the main buffer
        for (Int32 i = 0; i < numberOfBytesRead; i++)
        {
           dataBuffer.Enqueue(tempBuffer[i]);
        }
     }
  } 
  else ...
}

UPDATE:

I've re-written my class once again. Unit testing using the previous solution went fine but the real-world application example showed me why it is NOT possible for me to use the (otherwise great) suggestion of passing a Stream object into my method.

First off, my application relies on a constant TCP connection. If you use Stream.Read (which is possible) and there is no data to receive it will block the execution. If you specify a timeout an exception will be thrown if no data is received. This kind of behaviour is not acceptable for the (rather simple) application I need. I just need a no-frills, constant TCP connection. Therefore having the NetworkStream.DataAvailable property is paramount to my implementation.

The current solution:

I ended up writing an interface and a wrapper to NetworkStream. I also ended up passing the byte array for the temporary receive buffer into the method. Unit testing it now works rather well.

public static void ReadDataIntoBuffer(INetworkStream networkStream, Queue dataBuffer, byte[] tempRXBuffer)
{
    if ((networkStream != null) && (dataBuffer != null) && (tempRXBuffer != null))
    {
        // read the data from the network stream into the temporary buffer
        while(networkStream.DataAvailable)
        {
            Int32 numberOfBytesRead = networkStream.Read(tempRXBuffer, 0, tempRXBuffer.Length);

            // move all data into the main buffer
            for (Int32 i = 0; i < numberOfBytesRead; i++)
            {
                dataBuffer.Enqueue(tempRXBuffer[i]);
            }
        }
    }
    else ...
}

And here's the unit test that I use:

public void TestReadDataIntoBuffer()
{
    var networkStreamMock = new Mock<INetworkStream>();
    StringBuilder sb = new StringBuilder();

    sb.Append(_testMessageConstant1);
    sb.Append(_testMessageConstant2);
    sb.Append(_testMessageConstant3);
    sb.Append(_testMessageConstant4);
    sb.Append(_testMessageConstant5);


    // ARRANGE
    byte[] tempRXBuffer = Encoding.UTF8.GetBytes(sb.ToString());

    // return true so that the call to Read() is made
    networkStreamMock.Setup(x => x.DataAvailable).Returns(true);

    networkStreamMock.Setup(x => x.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>())).Callback(() =>
        {
            // after the call to Read() re-setup the property so that we
            // we exit the data reading loop again
            networkStreamMock.Setup(x => x.DataAvailable).Returns(false);

        }).Returns(tempRXBuffer.Length);

    Queue resultQueue = new Queue();

    // ACT
    ReadDataIntoBuffer(networkStreamMock.Object, resultQueue, tempRXBuffer);

    // ASSERT
    Assert.AreEqual(Encoding.UTF8.GetBytes(sb.ToString()), resultQueue.ToArray());
}

解决方案

You cannot mock the NetworkStream with moq since it is not an abstract class or an interface. You can however create an abstraction on top of it and change your method to accept an instance of that abstraction. It could be something like this:

public interface IMyNetworkStream
{
    int Read([In, Out] byte[] buffer, int offset, int size);
    bool DataAvailable {get;}
}

Now you create a class that implements the interface:

public class MyNetworkStream : IMyNetworkStream
{
     private NetworkStream stream;

     public MyNetworkStream(NetworkStream ns)
     {
         if(ns == null) throw new ArgumentNullException("ns");
         this.stream = ns;
     }

     public bool DataAvailable
     {
         get
         {
             return this.stream.DataAvailable;
         }
     }

     public int Read([In, Out] byte[] buffer, int offset, int size)
     {
         return this.stream.Read(buffer, offset, size);
     }

}

Now you can change your method signature to use an instance of IMyNetworkStream and use Moq to create a mock of IMyNetworkStream.

这篇关于如何起订量在一单元测试的NetworkStream?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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