单元测试代码依赖于DateTime.Now

时间:2017-02-05 19:38:58

标签: c# unit-testing

下面的Codewars.com说明。

  

创建一个传递生日的函数,并返回一个人多少年。

已经为您开发了测试用例。在创建测试用例时,程序员假设SystemClock类和StaticClock类之间存在共享接口。

public class SystemClock : IClock { ... }

public class StaticClock : IClock { ... }

SystemClock类需要实现返回DateTime的{​​{1}}方法

DateTime.Now方法需要实现一个StaticClock方法,该方法返回传递给其构造函数的DateTime值。

我们的UnitTest使用DateTime StaticClock实现来为我们的unittest提供一个恒定的时间值。考虑到时间总是在运动......如果我们只是根据IClock创建单元测试,那么我们的单元测试会随着时间的推移而失败。

使用DateTime.Now,我们可以注入我们的StaticClock方法应该返回的值,这样即使时间继续,我们的单元测试也会继续通过。

我的代码如下。

IClock.Now

当我尝试传入using System; namespace AgeFromDOB { public class Program { public class Kata { private DateTime staticClock; public Kata(StaticClock staticClock) { this.staticClock = staticClock.Now; } public int GetAgeFromDOB(DateTime birthday) { return staticClock.Year - birthday.Year; } } public interface IClock { DateTime Now { get; } } public class SystemClock : IClock { public DateTime Now { get; } public DateTime Method(DateTime Now) { return Now; } } public class StaticClock : SystemClock, IClock { public StaticClock(DateTime Now) { Method(Now); } } static void Main(string[] args) { Kata kata; kata = new Kata(new StaticClock(new DateTime(2008,09,3))); kata.GetAgeFromDOB(new DateTime(1984,04,23)); Console.ReadKey(); } } }

对象没有正确传递,我一直得到错误的结果。

我想知道在哪里研究或者我应该考虑解决这个问题的模式?

1 个答案:

答案 0 :(得分:2)

Kata依赖于实现具体性,因为它应该依赖于抽象。这将允许Kata灵活地接受抽象的不同实现。

public class Kata {
    private readonly IClock clock;

    public Kata(IClock clock) {
        this.clock = clock;
    }

    public int GetAgeFromDOB(DateTime birthday) {
        var now = clock.Now;    
        var age = now.Year - birthday.Year;
        if (birthday > now.AddYears(-age)) age--;
        return age;
    }
}

public interface IClock {
    DateTime Now { get; }
}

IClock的两个实现可以根据问题中的要求保持简单。

  

SystemClock类需要实现一个返回DateTime.Now

的DateTime方法
public class SystemClock : IClock {
    public DateTime Now { get { return DateTime.Now; } }
}
  

StaticClock方法需要实现一个DateTime方法,该方法返回传递给其构造函数的DateTime值。

public class StaticClock : IClock {
    public StaticClock(DateTime now) {
         this.Now = now;
    }

    public DateTime Now { get; private set; }
}

这应该可以让您获得理想的结果。