Unk*_*own 8 c# unit-testing mocking
通常的解决方案是将其隐藏在界面后面.
public class RecordService
{
private readonly ISystemTime systemTime;
public RecordService(ISystemTime systemTime)
{
this.systemTime = systemTime;
}
public void RouteRecord(Record record)
{
if (record.Created <
systemTime.CurrentTime().AddMonths(-2))
{
// process old record
}
// process the record
}
}
Run Code Online (Sandbox Code Playgroud)
在单元测试中,您可以使用模拟对象并决定返回什么
[TestClass]
public class When_old_record_is_processed
{
[TestMethod]
public void Then_it_is_moved_into_old_records_folder()
{
var systemTime = A.Fake<ISystemTime>();
A.CallTo( () => system.Time.CurrentTime())
.Returns(DateTime.Now.AddYears(-1));
var record = new Record(DateTime.Now);
var service = new RecordService(systemTime);
service.RouteRecord(record);
// Asserts...
}
}
Run Code Online (Sandbox Code Playgroud)
我不想在我的课程中注入另一个界面来获取当前时间.对于如此小的问题,感觉太重了.解决方案是使用具有公共功能的静态类.
public static class SystemTime
{
public static Func<DateTime> Now = () => DateTime.Now;
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以删除ISystemTime注入,RecordService就像这样
public class RecordService
{
public void RouteRecord(Record record)
{
if (record.Created < SystemTime.Now.AddMonths(-2))
{
// process old record
}
// process the record
}
}
Run Code Online (Sandbox Code Playgroud)
在单元测试中,我们可以轻松地模拟系统时间.
[TestClass]
public class When_old_record_is_processed
{
[TestMethod]
public void Then_it_is_moved_into_old_records_folder()
{
SystemTime.Now = () => DateTime.Now.AddYears(-1);
var record = new Record(DateTime.Now);
var service = new RecordService();
service.RouteRecord(record);
// Asserts...
}
}
Run Code Online (Sandbox Code Playgroud)
当然,所有这些都有不利之处.你正在使用公共字段(The HORROR!),所以没有人阻止你编写这样的代码.
public class RecordService
{
public void RouteRecord(Record record)
{
SystemTime.Now = () => DateTime.Now.AddYears(10);
}
}
Run Code Online (Sandbox Code Playgroud)
此外,我认为教育开发人员比创建抽象更好,只是为了保护他们不犯任何错误.其他可能的问题与运行测试有关.如果您忘记将功能恢复到原始状态,则可能会影响其他测试.这取决于单元测试运行器执行测试的方式.您可以使用相同的逻辑来模拟文件系统操作
public static class FileSystem
{
public static Action<string, string> MoveFile = File.Move;
}
Run Code Online (Sandbox Code Playgroud)
在我看来,使用公共函数实现这种功能(模拟时间,简单的文件系统操作)是完全可以接受的.它使代码更容易阅读,减少了依赖性,并且很容易在单元测试中进行模拟.