C# 将依赖项注入域模型
我有一个域模型,它有一个C# 将依赖项注入域模型,c#,unit-testing,dependency-injection,mocking,C#,Unit Testing,Dependency Injection,Mocking,我有一个域模型,它有一个OccurredOn字段,应该初始化为当前日期。通常我会将其设置为DateTime。现在在构造函数中 现在,我正试图创建一个IClock接口,以便模拟DateTime.Now进行单元测试。但是,现在我会将IClock依赖项注入我的域模型吗?我应该手动将实例化的时钟实例传递到构造函数中吗?我应该使用DI容器来解析构造函数中的依赖关系吗?我应该创建一个工厂类来给我一个初始化的对象吗?我离基地很远吗 为此: public class LogItem : KeyedEntityB
OccurredOn
字段,应该初始化为当前日期。通常我会将其设置为DateTime。现在在构造函数中
现在,我正试图创建一个IClock
接口,以便模拟DateTime.Now
进行单元测试。但是,现在我会将IClock
依赖项注入我的域模型吗?我应该手动将实例化的时钟
实例传递到构造函数中吗?我应该使用DI容器来解析构造函数中的依赖关系吗?我应该创建一个工厂类来给我一个初始化的对象吗?我离基地很远吗
为此:
public class LogItem : KeyedEntityBase
{
public LogItem(string message, string description, string status)
: this()
{
Message = message;
Description = description;
Status = status;
}
private LogItem() { }
public DateTime OccurredOn { get; set; }
public string Message { get; set; }
public string Description { get; set; }
public string Status { get; set; }
}
这:
或者这个:
var newItem = LogItemFactory.CreateNewLogItem("message", "desc", "status");
public LogItem(string message, string description, string status)
: this()
{
Message = message;
Description = description;
Status = status;
var clock = ObjectFactory.GetInstance<IClock>();
OccurredOn = clock.Now();
}
或者这个:
var newItem = LogItemFactory.CreateNewLogItem("message", "desc", "status");
public LogItem(string message, string description, string status)
: this()
{
Message = message;
Description = description;
Status = status;
var clock = ObjectFactory.GetInstance<IClock>();
OccurredOn = clock.Now();
}
公共登录项(字符串消息、字符串描述、字符串状态)
:此()
{
消息=消息;
描述=描述;
状态=状态;
var clock=ObjectFactory.GetInstance();
OccurredOn=时钟。现在();
}
最简单的方法是在
LogItem
中声明一个仅可用于测试的附加任务,如下所示:
public class LogItem : KeyedEntityBase
{
public LogItem(string message, string description, string status)
: this()
{
Message = message;
Description = description;
Status = status;
}
private LogItem() { }
internal LogItem(string message, string description, string status, DateTime dateTme)
: this(message, description, status)
{
OccuredOn = dateTime;
}
public DateTime OccurredOn { get; set; }
public string Message { get; set; }
public string Description { get; set; }
public string Status { get; set; }
}
然后使用InternalVisibleTo
属性授予测试程序集对内部的独占访问权
然后在测试中(并且只有在那里),您可以编写:
var newItem = new LogItem("message", "desc", "status", <date-whatever>);
var newItem=newlogitem(“消息”、“描述”、“状态”);
我很清楚,许多人会说,您不应该只为了使域模型可测试而向其添加代码,但我个人并不认为这一论点过于严肃,因为实践表明并非如此。请尝试以下方法:
//your object
public class LogItem {
public LogItem(string message, string description, string status) {
Message = message;
Description = description;
Status = status;
}
public System.DateTime OccurredOn { get; set; }
public string Message { get; set; }
public string Description { get; set; }
public string Status { get; set; }
}
public interface ILogFactory {
LogItem CreateNew(string message, string description, string status);
}
public class LogFactory: ILogFactory {
private readonly IClock clock;
public LogFactory(IClock clock) {
Requires.IsNotNull(clock, "clock");
this.clock = clock;
}
public LogItem CreateNew(string message, string description, string status) {
var item = new LogItem (message, description, status);
item.OccurredOn = clock.Now();
return item;
}
}
public interface IClock {
System.DateTime Now();
}
为了测试:
using NSubstitute; // see http://nsubstitute.github.io/
using NUF = NUnit.Framework;
[NUF.TestFixture]
public class LogFactoryTest {
[NUF.Test]public void CreateNew_should_call_now() {
var clock = Substitute.For<IClock>();
var fac = new LogFactory(clock);
fac.CreateNew("a", "b", "c");
clock.Received().Now();
}
[NUF.Test]public void CreateNew_should_set_correct_value() {
var clock = Substitute.For<IClock>();
var now = new System.DateTime(2014, 1, 15, 18, 0, 0);
clock.Now().Returns(now);
var fac = new LogFactory(clock);
LogItem log = fac.CreateNew("a", "b", "c");
NUF.Assert.That(log.OccurredOn, NUF.Is.EqualTo(now));
}
}
使用NSubstitute;//看见http://nsubstitute.github.io/
使用NUF=NUnit.Framework;
[num.TestFixture]
公共类LogFactoryTest{
[num.Test]public void CreateNew_应_调用_now(){
var clock=替换为();
var fac=新的日志工厂(时钟);
工厂新建(“a”、“b”、“c”);
clock.Received().Now();
}
[num.Test]public void CreateNew\u应该设置\u correct\u值(){
var clock=替换为();
var now=新系统日期时间(2014,1,15,18,0,0);
clock.Now()返回(现在);
var fac=新的日志工厂(时钟);
LogItem log=fac.CreateNew(“a”、“b”、“c”);
Assert.That(log.OccurredOn,NUF.Is.EqualTo(现在));
}
}
为什么不直接使用Moles(),这样你就可以忘记那个接口了?只是检查了一下,不,据我所知,它不在nuget上。我自己还没有试过,但似乎你必须安装它。我目前正在看这个,它似乎工作正常:是的,它也可以工作,没有界面可以摆弄。:)然后你会建议在我的公共部门中使用OccurredOn=DateTime。我想是这样的。这就是你们生产所需要的,对吗?是的。我不知道“InternalVisibleTo”属性。我会读起来的。谢谢