終於在下班前,把設置NetworkStream.Read 的 buffer 參數的難點搞定了。
第一次在網上 show 一下自己的代碼:

[TestFixture]


/**//// <summary>

/// FirstFixture 的摘要說明。

/// </summary>


public class FirstFixture ...{


MockRepository mocks = new MockRepository();

System.IDisposable order;


ITcpClient clIEntMock;

INetworkStream streamMock;

MainClass a;


private string[] expectedString;

private int expectedStringIndex;



public FirstFixture() ...{}


[SetUp]


public void SetUp() ...{

order = mocks.Ordered();

clientMock = (ITcpClient)mocks.CreateMock(typeof(ITcpClIEnt));

streamMock = (INetworkStream)mocks.CreateMock(typeof(INetworkStream));


a = new MainClass(clIEntMock);

clIEntMock.Connect(serverIp, serverPort);

Expect.Call(clIEntMock.GetStream()).Return(streamMock);

Expect.On(clientMock).Call(clIEntMock.GetLocalPort()).Return(localPort);

}


[TearDown]


public void TearDown() ...{

mocks.VerifyAll();

}


delegate bool NetworkStreamWriteDelegate(byte[] actualBuffer, int actualOffset, int actualSize);

delegate int NetworkStreamReadDelegate(byte[] buffer, int offset, int size);



bool NormalWriteMessageAssert(byte[] actualBuffer, int actualOffset, int actualSize) ...{

expectedString[0] = "prefix";

string actualBufferString = Encoding.ASCII.GetString(actualBuffer);

Assert.AreEqual(expectedString[0], actualBufferString.Substring(0, expectedString[0].Length));

//assert clIEnt.write()來的timestamp

System.DateTime actualTimeStamp = System.DateTime.ParseExact(actualBufferString.Substring(expectedString[0].Length, 20), "dd-MMM-yyyy HH:mm:ss", System.Globalization.DateTimeFormatInfo.InvariantInfo);

// 時間差小於2秒

Assert.Greater(2, System.Math.Abs(System.DateTime.Now.Subtract(actualTimeStamp).TotalSeconds));


expectedString[0] = "postfix";

Assert.AreEqual(expectedString[0], actualBufferString.Substring(actualBufferString.Length - expectedString[0].Length, expectedString[0].Length));


return true;

}



int SetReadBuffer(byte[] buffer, int offset, int size) ...{

byte[] expectedBuffer = Encoding.ASCII.GetBytes(expectedString[expectedStringIndex++]);


for (int pos = 0; pos < expectedBuffer.Length; pos++) ...{

buffer[pos] = expectedBuffer[pos];

}

return expectedBuffer.Length;

}


[Test]


public void Normal() ...{

expectedString = new string[3];


expectedString[0] = "static write string";

streamMock.Write(Encoding.ASCII.GetBytes(expectedString[0]), 0, expectedString[0].Length);


// write的buffer中,包含了當前的時間戳信息。利用Callback實現復雜的assert

streamMock.Write(null, 0, 0);

LastCall.Callback(new NetworkStreamWriteDelegate(NormalWriteMessageAssert));


// 利用Expect.Do()和delegate,實現對多次Stream.Read()的mock

// 這是在Rhino.Mocks google group中Stream.Read的貼子的基礎上完善的。

// 感謝Terriy

byte[] responseBuffer = new byte[1024];

expectedStringIndex = 1;

expectedString[1] = "first server response";

Expect.Call(streamMock.Read(responseBuffer, 1, 1024)).Constraints(Is.TypeOf(typeof(byte [])), Is.Equal(0), Is.Equal(responseBuffer.Length))

.Do(new NetworkStreamReadDelegate(SetReadBuffer));


expectedString[2] = "server second string";

Expect.Call(streamMock.Read(responseBuffer, 2, 1024)).Constraints(Is.TypeOf(typeof(byte [])), Is.Equal(0), Is.Equal(responseBuffer.Length))

.Do(new NetworkStreamReadDelegate(SetReadBuffer));


clIEntMock.Close();


order.Dispose();

mocks.ReplayAll();

a.Interact();

}