简体   繁体   中英

Mock Networkstream.Read

I've been trying to mock a network stream for some unit tests.

So far, using Moq the best I've come up with is to use a wrapper for the stream and then mock my interface.

public interface INetworkstreamWrapper
{
    int Read(byte[] buffer, int offset,int size);

    void Flush();

    bool DataAvailable { get; }

    bool CanRead { get; }

    void close();
}

Question is, whilst that gives me a start, I actually want to test some byte array values as read into my read buffer. How can I return some test data into the buffer when calling Read() on the mock object?

You can use Setup to do this:

[Test]
public void MockStreamTest()
{
    var mock = new Mock<INetworkstreamWrapper>();
    int returnValue = 1;
    mock.Setup(x => x.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>()))
                     .Returns((byte[] r,int o, int s) =>
                                  {
                                      r[0] = 1;
                                      return returnValue;
                                  });
    var bytes = new byte[1024];
    var read = mock.Object.Read(bytes , 1, 1);
    //Verify the the method was called with expected arguments like this:
    mock.Verify(x => x.Read(bytes, 1, 1), Times.Once());
    Assert.AreEqual(returnValue, read);
    Assert.AreEqual(1,bytes[0]);
}

You can use a callback to gain access to the passed parameter and alter them:

public void TestRead()
{
  var streamMock = new Mock<INetworkstreamWrapper>();

   streamMock
            .Setup(m => m.Read(It.IsAny<byte[]>(), 
                               It.IsAny<int>(), 
                               It.IsAny<int>()))
            .Callback((byte[] buffer, int offset, int size) => buffer[0] = 128);

   var myBuffer = new byte[10];
   streamMock.Object.Read(myBuffer,0,10);

   Assert.AreEqual(128, myBuffer[0]);
}

But I would suggest you rethink your strategy about that kind of mocking, see: http://davesquared.net/2011/04/dont-mock-types-you-dont-own.html

Maybe you could write an integration test instead, or make your code depend on the abstract Stream class.

In your test you could then use a MemoryStream to check your class correct behaviour when fetching data from the Stream.

In Rhinomocks, this is very easy, as the important methods on NetworkStream are virtual, and so you can simply create a stub using the MockRepository. Even better, it understands that the byte array passed to the Read method is an output array, so you can completely stub out a call to Read() using this code:

NetworkStream stream = MockRepository.GenerateStub<NetworkStream>();
stream.Stub(x => x.Read(Arg<byte[]>.Out(bytes).Dummy, Arg<int>.Is.Anything, Arg<int>.Is.Anything))
      .Return(bytes.Length);

No wrapper required.

I've had very little experience with Moq but I'd be surprised if it didn't support something similar.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM