我有以下方法,我想进行单元测试:
public void Upload(string identifier, Stream data)
{
var startTime = SystemTime.Now;
innerDataIntegrationInterface.Upload(identifier, data);
var endTime = SystemTime.Now;
TimeSpan totalUploadTime = endTime.Subtract(startTime);
float transferRate = data.Length / (float)(totalUploadTime.Seconds + totalUploadTime.Milliseconds);
m_log.Info(string.Format("Total uploading time for '{0}' was {1:00}.{2:000000} milliseconds transfered at {3} bytes/sec", identifier, totalUploadTime.Seconds, totalUploadTime.Milliseconds, transferRate));
}
基本上我已经注入了SystemTime对象,所以我可以在我的测试中设置它,但我无法弄清楚该做什么,以便startTime和endTime变量得到不同的值,所以我可以断言m_log.Info方法使用totalUploadTime和transferRate变量的正确值调用。
任何想法都会受到赞赏。
答案 0 :(得分:4)
时钟的想法 - 有些东西可以获得当前时间 - 实际上是你依赖的服务。如果您通过某个接口(IClock
)明确地依赖 ,就像您使用任何其他服务一样。然后,您可以创建一个“生产”实现,该实现委托给System.DateTime.UtcNow
或System.DateTime.Now
以及假实现或模拟进行测试。
根据我的经验,值得假装你可以设置,推进等而不是使用模拟框架来实现这个特定场景 - 这是我见过的一种技术并且使用了很多(这就是Noda Time支持的原因)它带有IClock
接口和StubClock
实现。)
答案 1 :(得分:1)
你可以让你的Mock SystemTime
对象在Now
Getter中增加它的值吗?这会让他们与众不同。
答案 2 :(得分:1)
处理此问题的一种方法是将代码的复杂部分(您真正想要测试的部分)提取到另一个类或方法中并对其进行测试。
在这种情况下,这将涉及提取逻辑以将传输速率计算为一个单独的方法,该方法需要两个时间参数和传输的数量。
(又名,“Gather,Then Use”来自Mock-Eliminating Patterns。)
答案 3 :(得分:1)
如果innerDataIntegrationInterface.Upload
是模拟界面的一部分,您可以模拟Upload
方法,如:
var mock = new Mock<innerDataIntegrationInterface>();
mock.Setup(m => m.Upload(identifier, data)).Callback<object>(
c =>
{
//increment SystemTime.Now
//or call
//Thread.Sleep(1); to sleep for microsecond
});
以上是在c#中使用 Moq