Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将依赖项注入域模型_C#_Unit Testing_Dependency Injection_Mocking - Fatal编程技术网

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”属性。我会读起来的。谢谢