在NUnit和Moq中围绕DateTime窗口进行单元测试[重复]

问题描述 投票:1回答:2

这个问题在这里已有答案:

我跟随TDD Kata 'Greeter',其中我必须创建一个类,该方法根据调用它的时间返回不同的输出。所以我有这个类Greeter

public class Greeter : Greeter
{
    public DateTime time
    {
        get
        {
            return DateTime.Now;
        }
    }

    public Greeter() { }

    public string greet(string name)
    {
        string greeting = "Hello ";

        name = name.Substring(0, 1).ToUpper() + name.Substring(1);

        if(name.Length > 36)
        {
            name = name.Substring(0, 35);
        }

        if(time.Hour >= 6 && time.Hour <= 12)
        {
            greeting = "Good morning";
        } else if (time.Hour >= 18 && time.Hour <= 22)
        {
            greeting = "Good evening";
        } else if (time.Hour >=22 || time.Hour < 6)
        {
            greeting = "Good night";
        }

        return $"{greeting} {name}";
   }

}

Greeter实施IGreeter

    public interface IGreeter
    {
        DateTime time
        {
            get;
        }
        string greet(string name);
    }

现在在单元测试方面,我必须在一天的不同时间测试以查看响应:上午的Good morning ~,晚上的Good evening ~,晚上的Good night ~和默认情况下的Hello ~

所以我的问题是,如何在不过多修改类的情况下设计这些时间限制的单元测试?据我所知,改变类只是为了启用单元测试被认为是代码味道。有没有办法可以使用NUnit和Moq实现这一目标?到目前为止我看到的最好的解决方案是在构造函数中使用DI时间提供程序,但是我不想在每个实例化中提供通用时间提供程序来启用测试。

任何指导将不胜感激。

c# .net nunit moq
2个回答
1
投票

只需在调用greet方法时传入DateTime对象。例

greeter.greet(DateTime.Now, "steve");

它将删除您在time方法中对DateTime.Now的依赖。然后你可以轻松地进行单元测试。


0
投票

您应该从代码中调用DateTime类。在此处使用界面并从外部提供实施。

public interface IDateTime
{
    DateTime Now();
}

public class Foo
{
    IDateTime dt;

    public DateTime GetActualTime
    {
        get
        {
            return dt.Now();
        }
    }

    public Foo(IDateTime dt)
    {
        this.dt = dt;
    }

    public string Bar()
    {
        return this.GetActualTime().ToString();
   }
}

为了测试,所以不使用Moq,我们实现了一个特定的实现。

public class DateTimeTest : IDateTime
{
    DateTime dt;
    public DateTimeTest(DateTime testTime)
    {
        this.dt = testTime;
    }

    public DateTime Now()
    {
        return dt;
    }
}

并在测试中使用它

// Set your test time
DateTimeTest testTime = new DateTime(2019, 5, 1, 18, 04, 30);

// Create your sut
foo sut = new Foo(testTime);

// Call the function using the defined time
var result = sut.Bar();

在生产代码中,您需要一个使用.NET DateTime对象的实现。

另见:DateTime Interface to be used for unit testing

© www.soinside.com 2019 - 2024. All rights reserved.