使用 NUnit 对 DateTime 控制器进行单元测试

Unit testing DateTime controller using NUnit

我正在创建一个 React / .NET Core 项目,其中一个页面显示当前日期和时间。我的控制器class如下:

namespace TestingReactDotNet.Controllers {

    [Route ("api/[controller]")]
    public class DayTodayController : Controller {

        [HttpGet, Route ("GetDate")]
        public  string GetDate () {

            var info = $"Today is {DateTime.Now.ToString("dddd, dd MMMM yyyy")} and the time is {DateTime.Now.ToString("hh:mm tt")}";
            return info;

        }
    }
}

我正在尝试对此进行单元测试并模拟日期和时间,但我正在努力做到这一点(我查看了其他 Stack Overflow 问题并进行了 Google 搜索,但我仍然遇到问题)。本来想用Moq,但是好像不能这样?

这是我目前的测试结果:

namespace TestingReactDotNetTests
{
    public class DayTodayTests
    {
        [Test]
        public void ReturnsDateAndTime()
        {
            var controller = new DayTodayController();
            string result = controller.GetDate();
            string expected = "Today is Tuesday 27 August 2019 and the time is 10:00";
            Assert.AreEqual(expected, result); 


        }
    }
}

我的问题是 - 如何设置日期和时间,以便在字符串中调用 DateTime.Now 时,它不是当前日期和时间?

实现此目的的通常方法是在您正在测试的对象的构造函数中注入一个 date/time 提供程序。例如:

public interface IDateTimeProvider
{
    DateTime Now();
}

以及该接口的具体实现:

public class DateTimeProvider : IDateTimeProvider
{
    public DateTime Now() 
    {
        return Datetime.Now;
    }
}

你需要添加IDateTimeProvider到DI容器,

类似于

services.AddSingleton<IDateTimeProvider, DateTimeProvider>(); 

但这取决于您的设置方式、使用的框架等。

你的控制器会变成这样:

[Route ("api/[controller]")]
public class DayTodayController : Controller
{
    private readonly IDateTimeProvider _dateTimeProvider;

    public DayTodayController(IDateTimeProvider dateTimeProvider)
    {
        _dateTimeProvider = dateTimeProvider;
    }

    [HttpGet, Route ("GetDate")]
    public  string GetDate () {
        var dateTime = _dateTimeProvider.Now();
        var info = $"Today is {dateTime.ToString("dddd, dd MMMM yyyy")} and the time is {dateTime.ToString("hh:mm tt")}";
        return info;
    }
}

注意 DateTime 对变量的赋值。多次调用 DateTime.Now 会给出不同的值,因此您可能希望对一个实例进行操作以获得所需的行为。

现在您可以使用接口的非脆弱模拟实现进行测试:

public class DayTodayTests
{
    [Test]
    public void ReturnsDateAndTime()
    {
        //Arrange
        var mockedDateTimeProvider = new Mock<IDateTimeProvider>();
        mockedDateTimeProvider.Setup(dtp => dtp.Now()).Returns(new DateTime(2019, 8, 27, 10, 0, 0));
        var controller = new DayTodayController(mockedDateTimeProvider.Object);

        //Act
        string result = controller.GetDate();

        //Assert
        string expected = "Today is Tuesday 27 August 2019 and the time is 10:00 AM";

        Assert.AreEqual(expected, result); 
    }
}