对具有sytem.DateTime值C#的属性进行单元测试

时间:2018-07-26 12:42:24

标签: c# vs-unit-testing-framework

如何为以下代码块编写单元测试

public class Hotel
{
    DateTime CLOSING_TIME // imported from somewhere else
    public bool IsOpen
    {
        get
        {
            return DateTime.Now <= CLOSING_TIME
        }
    }
}

我尝试跟随其中任何一个都会一直失败,我如何确保两个单元测试用例每次都会通过:

[TestFixture]
public void ShouldBeOpen()
{
    var Hot= new Hotel();
    Assert.True(Hot.IsOpen); 
}

[TestFixture]
public void ShouldBeOpen()
{
    var Hot= new Hotel();
    Assert.False(Hot.IsOpen); 
}

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:2)

您的测试有很多问题:

  • 它们是不确定的(正如您已经注意到的),因为它们依赖时间
  • 它们是多余的(第二项测试与第一个测试完全相同)
  • 从您键入的语义来看,您似乎需要花时间而不是完整的DateTime,而您无法在IsOpen中表达出来

我个人还认为,这种琐碎的测试是没有用的,因为它没有为该测试增加任何价值:

[TestFixture]
public void ShouldBeOpen()
{
    Assert.True(DateTime.Now <= CLOSING_TIME);
}

不过,IsOpen中的微小变化可以改善您的实施和测试代码,并使代码保持简单(无需存根/模拟系统日期):

public sealed class Hotel
{
    public bool IsOpenAt(DateTime time) => time.TimeOfDay <= CLOSING_TIME.TimeOfDay;
}

通过这类测试可以真正测试一些业务断言:

[TestFixture]
public void ShouldBeOpen()
{
    Assert.True(new Hotel().IsOpenAt(CLOSING_TIME));
}

[TestFixture]
public void ShouldNotBeOpen()
{
    Assert.False(new Hotel().IsOpenAt(CLOSING_TIME.AddMinutes(1)));
}

注意

尽管没有要求,但我想解决一些问题:CLOSING_TIME。在我看来,该字段可疑。确实,我怀疑您设置此值的方式会导致某物Hotel的不必要耦合。如果不是这种情况,我建议您将这个值作为构造函数的参数来请求,以实现更好的去耦:

public sealed class Hotel
{
    private readonly DateTime _closingTime;
    public Hotel(DateTime closingTime) => _closingTime = closingTime;
    public bool IsOpenAt(DateTime time) => time.TimeOfDay <= _closingTime.TimeOfDay;
}

答案 1 :(得分:0)

我将下面的代码组合在一起以模拟一个时间接口,您可以将其用于单元测试。使用此功能,您可以将时间设置为您指定的实时时间或虚假时间。在单元测试中,我经常使用这种方法。这称为依赖注入或构造函数注入,对单元测试非常有用。

    class Hotel
    {
        public DateTime ClosingTime = DateTime.ParseExact("17:00:00", "HH:ii:ss", CultureInfo.InvariantCulture);
        public IStubClock Clock;
        public bool IsOpen
        {
            get
            {
                return Clock.Now.TimeOfDay <= ClosingTime.TimeOfDay;
            }
        }
        public Hotel(IStubClock clock)
        {
            Clock = clock;
        }
    }

使用此接口,您可以模拟任何DateTime.Now结构

    public interface IStubClock
    {
        DateTime Now { get; }
    }

假的变体

    public class FakeClock : IStubClock
    {
        private DateTime _now;
        public DateTime Now
        {
            get
            {
                return _now;
            }
        }

        public FakeClock(DateTime now)
        {
            _now = now;
        }
    }

还有一个真正的变体

    public class RealClock : IStubClock
    {
        public DateTime Now
        {
            get
            {
                return DateTime.Now;
            }
        }
    }

然后您可以在测试中使用它们

    class Program
    {
        static void Main(string[] args)
        {
            IStubClock fakeClock = new FakeClock(new DateTime(1, 1, 1, 10, 0, 0)); //time is set to 10am
            IStubClock realClock = new RealClock(); //time is set to whatever the time now is.
            Hotel hotel1 = new Hotel(fakeClock); //using fake time
            Hotel hotel2 = new Hotel(realClock); //using the real time
        }
    }