Как проверить логику, которая зависит от текущей даты - PullRequest
8 голосов
/ 17 февраля 2010

У меня есть этот метод, который зависит от текущей даты. Он проверяет, является ли сегодня солнце, понедельник, вторник или среда, а затем дает 5 дней времени для прибытия отправленных товаров. Если это четверг, пятница или суббота, то это дает 6 дней времени для учета выходных.

private DateTime GetEstimatedArrivalDate()
{
    DateTime estimatedDate; 
    if (DateTime.Now.DayOfWeek >= DayOfWeek.Thursday)
    {
        estimatedDate = DateTime.Now.Date.AddDays(6);
    }
    else
    {
        estimatedDate = DateTime.Now.Date.AddDays(5);
    }
    return estimatedDate; 
}

Фактическая логика оценки более сложна. Я упростил это для целей этого вопроса. Мой вопрос: как мне написать модульный тест для чего-то подобного, который зависит от сегодняшней даты?

Ответы [ 8 ]

19 голосов
/ 17 февраля 2010

Вам необходимо передать текущую дату в качестве параметра:

private DateTime GetEstimatedArrivalDate(DateTime currentDate)
{
    DateTime estimatedDate; 
    if (currentDate.DayOfWeek >= DayOfWeek.Thursday)
    {
        estimatedDate = currentDate.AddDays(6);
    }
    else
    {
        estimatedDate = currentDate.AddDays(5);
    }
    return estimatedDate; 
}

В реальном коде вы называете это так:

DateTime estimatedDate = GetEstimatedArrivalDate(DateTime.Now.Date);

Затем вы можете проверить это следующим образом:

DateTime actual = GetEstimatedArrivalDate(new DateTime(2010, 2, 10));
DateTime expected = ...;
// etc...

Обратите внимание, что это также исправляет потенциальную ошибку в вашей программе, когда дата меняется между последовательными вызовами на DateTime.Now.

10 голосов
/ 17 февраля 2010

Вообще говоря, вы хотите абстрагироваться от способа получения текущей даты и времени за интерфейсом, например:

public interface IDateTimeProvider
{
    DateTime Now { get; }
}

Реальная услуга будет:

public class DateTimeProvider: IDateTimeProvider
{
    public DateTime Now
    {
        get
        {
            return DateTime.Now;
        }
    }
}

И тестовый сервис будет:

public class TestDateTimeProvider: IDateTimeProvider
{
    private DateTime timeToProvide;
    public TestDateTimeProvider(DateTime timeToProvide)
    {
        this.timeToProvide = timeToProvide;
    }

    public DateTime Now
    {
        get
        {
            return timeToProvide;
        }
    }
}

Для служб, которым требуется текущее время, попросите их взять IDateTimeProvider в качестве зависимости. На самом деле, передайте новый DateTimeProvider (); когда вы компонент, передайте новый TestDateTimeProvider (timeToTestFor).

3 голосов
/ 18 февраля 2010

Заставьте ваш класс принять параметр IClock (через конструктор или свойство)

interface IClock
{
    DateTime Now { get; }
}

Затем вы можете использовать поддельную реализацию для тестирования

class FakeClock : IClock
{
    DateTime Now { get; set }
}

и реальную реализациюостальное время.

class SystemClock : IClock
{
    DateTime Now { get { return DateTime.Now; } }
}
1 голос
/ 17 февраля 2010

Я дам спорный ответ, не проверяйте его.

Логика тривиальна и не имеет нулевых зависимостей, я верю в хорошее покрытие кода, но не в тех случаях, когда это увеличивает сложность без реальной выгоды.

0 голосов
/ 18 февраля 2010

Я бы предложил сделать это, как Марк предлагает , но с добавлением перегруженного вызова для производственного использования, который не принимает параметров и использует DateTime.Now

private DateTime GetEstimatedArrivalDate()
{
    return GetEstimatedArrivalDate(DateTime.Now);
}

private DateTime GetEstimatedArrivalDate(DateTime currentDate)
{
    DateTime estimatedDate; 
    if (currentDate.DayOfWeek >= DayOfWeek.Thursday)
    {
        estimatedDate = currentDate.AddDays(6);
    }
    else
    {
        estimatedDate = currentDate.AddDays(5);
    }
    return estimatedDate; 
}
0 голосов
/ 17 февраля 2010

Один «общий» способ сделать это - «подделать» текущую системную дату (это можно сделать несколькими способами), а затем протестировать ваш код на «известные» даты.

Еще один интересный способ - немного изменить реализацию:

private DateTime GetEstimatedArrivalDate()
{
    return GetEstimatedArrivalDate(DateTime.Now);
}

private DateTime GetEstimatedArrivalDate(DateTime forDate)
{
    DateTime estimatedDate; 
    if (forDate.DayOfWeek >= DayOfWeek.Thursday)
    {
        estimatedDate = forDate.Date.AddDays(6);
    }
    else
    {
        estimatedDate = forDate.Date.AddDays(5);
    }
    return estimatedDate; 
}

А затем используйте метод с параметром для проверки «немедленных» дат.

0 голосов
/ 17 февраля 2010

Вы можете передать делегата, который возвращает DateTime.Now во время обычного выполнения, а затем при прохождении теста в другом делегате, который возвращает фиксированную дату, и подтвердить свой результат на основании этого.

0 голосов
/ 17 февраля 2010

Похоже, что существует достаточно ограниченное количество случаев, чтобы вы могли проверить их в явном виде. Метод зависит от сегодняшней даты, но выходные данные зависят только от дня недели, и у каждой даты есть день недели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...