简体   繁体   English

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

[英]Unit testing DateTime controller using NUnit

I am creating a React / .NET Core project and one of the pages displays the current date and time. 我正在创建一个React / .NET Core项目,其中一个页面显示当前的日期和时间。 My controller class is as follows: 我的控制器类如下:

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;

        }
    }
}

I am trying to unit test this and mock the date and time but am struggling to do this (I have looked at other Stack Overflow questions and Googled but I am still having trouble). 我正在尝试对此进行单元测试并模拟日期和时间,但我正在努力做到这一点(我已经查看了其他Stack Overflow问题和谷歌搜索,但我仍然遇到麻烦)。 I originally wanted to use Moq but it seems that this may not be possible? 我原本想使用Moq但似乎这可能不可能?

Here is what I have so far for my test: 这是我到目前为止测试的内容:

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); 


        }
    }
}

My question is - how can I set the date and time so that when DateTime.Now is called in the string, it isn't the current date and time? 我的问题是 - 如何设置日期和时间,以便在字符串中调用DateTime.Now时,它不是当前的日期和时间?

The usual way to achieve this is to inject a date/time provider in the constructor of the object you are testing. 实现此目的的常用方法是在要测试的对象的构造函数中注入日期/时间提供程序。 For example: 例如:

public interface IDateTimeProvider
{
    DateTime Now();
}

and a concrete implementation of that interface: 以及该接口的具体实现:

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

You need to add IDateTimeProvider to the DI container, 您需要将IDateTimeProvider添加到DI容器中,

something like 就像是

services.AddSingleton<IDateTimeProvider, DateTimeProvider>(); 

but it depends on how you have set it up, which framework you are using etc. 但这取决于你如何设置,你正在使用哪个框架等。

You controller would change to something like this: 您的控制器将更改为以下内容:

[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;
    }
}

Note the assignment of the DateTime to a variable. 请注意将DateTime分配给变量。 Calling DateTime.Now multiple times will give different values, so you would want to operate on one instance to get the desired behavior. 多次调用DateTime.Now将给出不同的值,因此您希望在一个实例上操作以获得所需的行为。

And now you can test with a non-brittle mocked implementation of the interface: 现在,您可以使用非脆弱的模拟实现接口进行测试:

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); 
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM