我一直在尝试为某些单元测试模拟网络流。
到目前为止,使用Moq我得到的最好的方法是使用流的包装器然后模拟我的界面。
public interface INetworkstreamWrapper
{
int Read(byte[] buffer, int offset,int size);
void Flush();
bool DataAvailable { get; }
bool CanRead { get; }
void close();
}
问题是,虽然这给了我一个开始,但实际上我想测试一些字节数组值作为读入我的读缓冲区。在模拟对象上调用Read()时,如何将一些测试数据返回缓冲区?
答案 0 :(得分:4)
您可以使用Setup
执行此操作:
[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]);
}
答案 1 :(得分:4)
您可以使用回调来访问传递的参数并更改它们:
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]);
}
但我建议你重新考虑一下这种嘲弄的策略,请参阅: http://davesquared.net/2011/04/dont-mock-types-you-dont-own.html
也许您可以编写集成测试,或者让您的代码依赖于抽象的Stream类。
在测试中,您可以使用MemoryStream在从Stream中获取数据时检查类的正确行为。
答案 2 :(得分:0)
在Rhinomocks中,这非常简单,因为NetworkStream上的重要方法是虚拟的,因此您可以使用MockRepository简单地创建存根。更好的是,它理解传递给Read方法的字节数组是一个输出数组,因此您可以使用以下代码完全删除对Read()的调用:
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);
不需要包装。
我对Moq的经验很少,但如果它不支持类似的东西,我会感到惊讶。