obaylis
obaylis

Reputation: 3034

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?

Upvotes: 6

Views: 1922

Answers (3)

Clarkeye
Clarkeye

Reputation: 929

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.

Upvotes: 1

Johan Larsson
Johan Larsson

Reputation: 17580

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

Upvotes: 4

foobarcode
foobarcode

Reputation: 2337

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.

Upvotes: 4

Related Questions