终于在下班前,把设置NetworkStream.Read 的 buffer 参数的难点搞定了。
2008.01第一次在网上 show 一下自己的代码:
又refact了一下,抽取出 MockHelper class
namespace
aaa.bbb.Test
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//// <summary>
/// MockHelper 的摘要说明。
/// Rhino.Mocks 2.9.5 for .Net 1.1
/// </summary>
/// <remarks>
/// 由于 Rhino.Mocks 是在 VerifyAll() 时,才去取变量的值作为 Expected,
/// 而不是在类似 Expect.Call() 时马上取变量的值作为 Expected
/// 因此创建本 Helper 类,利用 Queue 保存 Expect.Call() 时的 Expected Value,
/// 供Rhino.Mocks在 VerifyAll() 时获取
/// </remarks>
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public class MockHelper ...{
private Queue expectedStrings;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
public delegate bool NetworkStreamWriteDelegate(byte[] actualBuffer, int actualOffset, int actualSize);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
public delegate int NetworkStreamReadDelegate(byte[] buffer, int offset, int size);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public MockHelper() ...{
expectedStrings = new Queue(5);
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public void SetExpectedString(string aString) ...{
expectedStrings.Enqueue(aString);
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//// <summary>
/// 当 Message 中包含有“实际时间”时,根据时间戳标记,分段 Assert
/// </summary>
/// <param name="actualBuffer"></param>
/// <param name="actualOffset"></param>
/// <param name="actualSize"></param>
/// <returns></returns>
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public bool AssertWriteMessageWithTimeStamp(byte[] actualBuffer, int actualOffset, int actualSize) ...{
Assert.AreEqual(0, actualOffset);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
string expected = (string)expectedStrings.Dequeue();
string pat = @">%d([-:dMyHms ]+)</";
Regex re = new Regex(pat);
MatchCollection mc = re.Matches(expected);
string actualBufferString = Encoding.ASCII.GetString(actualBuffer);
if (0 == mc.Count) System.Console.Out.WriteLine("Non regex matched {0} {1}", pat, expected);
Assert.AreEqual(expected.Substring(0, mc[0].Groups[0].Index - 1), actualBufferString.Substring(0, mc[0].Groups[0].Index - 1));
System.DateTime actualTimeStamp;
Match m;
int startPos;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
for (int i = 0; i < mc.Count - 1; i++) ...{
m = mc[i];
//18-Dec-2007 17:57:10 "dd-MMM-yyyy HH:mm:ss"
actualTimeStamp = System.DateTime.ParseExact(actualBufferString.Substring(m.Groups[1].Index - 2 * i, m.Groups[1].Length)
, m.Groups[0].Value
, System.Globalization.DateTimeFormatInfo.InvariantInfo);
// 时间差小于2秒
Assert.Greater(2, System.Math.Abs(System.DateTime.Now.Subtract(actualTimeStamp).TotalSeconds));
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
Assert.AreEqual(expected.Substring(m.Groups[1].Index + m.Groups[1].Length, mc[i+1].Groups[1].Index - m.Groups[1].Index)
, actualBufferString.Substring(actualBufferString.Length - expected.Length, expected.Length));
}
m = mc[mc.Count - 1];
actualTimeStamp = System.DateTime.ParseExact(actualBufferString.Substring(m.Groups[1].Index - 2 * mc.Count, m.Groups[1].Length)
, m.Groups[1].Value
, System.Globalization.DateTimeFormatInfo.InvariantInfo);
// 时间差小于2秒
Assert.Greater(2, System.Math.Abs(System.DateTime.Now.Subtract(actualTimeStamp).TotalSeconds));
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
startPos = m.Groups[1].Index + m.Groups[1].Length;
Assert.AreEqual(expected.Substring(startPos)
, actualBufferString.Substring(startPos - 2 * mc.Count));
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
Assert.AreEqual(expected.Length - 2 * mc.Count, actualSize);
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public int GetReadBuffer(byte[] buffer, int offset, int size) ...{
byte[] expectedBuffer = Encoding.ASCII.GetBytes(expectedStrings.Dequeue().ToString());
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
for (int pos = 0; pos < expectedBuffer.Length; pos++) ...{
buffer[pos] = expectedBuffer[pos];
}
return expectedBuffer.Length;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
}
}
[TestFixture]
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/// <summary>
/// FirstFixture 的摘要说明。
/// Rhino.Mocks 2.9.6 for .Net1.1
/// </summary>
public
class
FirstFixture
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
MockRepository mocks = new MockRepository();
System.IDisposable order;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
ITcpClient clientMock;
INetworkStream streamMock;
MockHelper aHelper;
MainClass a;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public FirstFixture() ...{}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
[SetUp]
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public void SetUp() ...{
order = mocks.Ordered();
clientMock = (ITcpClient)mocks.CreateMock(typeof(ITcpClient));
streamMock = (INetworkStream)mocks.CreateMock(typeof(INetworkStream));
aHelper = new MockHelper();
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
a = new MainClass(clientMock);
clientMock.Connect(serverIp, serverPort);
Expect.Call(clientMock.GetStream()).Return(streamMock);
Expect.On(clientMock).Call(clientMock.GetLocalPort()).Return(localPort);
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
[TearDown]
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public void TearDown() ...{
mocks.VerifyAll();
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
[Test]
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public void Normal() ...{
expectedString = new string;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
expectedString = "static %yyyy-mm-dd write string";
streamMock.Write(Encoding.ASCII.GetBytes(expectedString), 0, expectedString.Length);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// write的buffer中,包含了当前的时间戳信息。利用Callback实现复杂的assert
streamMock.Write(null, 0, 0);
aHelper.SetExpectedString(expectedRequestBody);
LastCall.Callback(new MockHelper.NetworkStreamWriteDelegate(aHelper.AssertNormalWriteMessage));
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// 利用Expect.Do()和delegate,实现对多次Stream.Read()的mock
// 这是在Rhino.Mocks google group中Stream.Read的贴子的基础上完善的。
// 感谢Terriy
byte[] responseBuffer = new byte[1024];
aHelper.SetExpectedString("first server response");
Expect.Call(streamMock.Read(responseBuffer, 1, 1024)).Constraints(Is.TypeOf(typeof(byte [])), Is.Equal(0), Is.Equal(responseBuffer.Length))
.Do(new MockHelper.NetworkStreamReadDelegate(aHelper.SetReadBuffer));
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
aHelper.SetExpectedString("server second string");
Expect.Call(streamMock.Read(responseBuffer, 2, 1024)).Constraints(Is.TypeOf(typeof(byte [])), Is.Equal(0), Is.Equal(responseBuffer.Length))
.Do(new MockHelper.NetworkStreamReadDelegate(aHelper.SetReadBuffer));
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
clientMock.Close();
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
order.Dispose();
mocks.ReplayAll();
a.Interact();
}