Модульное тестирование NodaTime с псевдонимом DateTimeZone - PullRequest
1 голос
/ 14 января 2020

Я работаю над модульным тестом для моего метода расширения.

public static DateTimeZone GetDateTimeZone(this IDateTimeZoneProvider dateTimeZoneProvider, String timezoneId)
{
    DateTimeZone dateTimeZone;
    if ((dateTimeZone = dateTimeZoneProvider.GetZoneOrNull(timezoneId)) != null)
        return dateTimeZone;    

    // Continues to try and map from TimeZoneInfo if dateTimeZone == null
}

При модульном тестировании этого метода тест не пройден, поскольку псевдоним возвращается для идентификатора DateTimeZone.

[TestMethod]
public void GetDateTimeZone_DateTimeZoneProviderHasTimezoneIdAsAlias_ReturnsDateTimeZone()
{
    var expectedTimezoneId = "America/New_York";
    var timezoneId = "US/Eastern";
    var dateTimeZone = _dateTimeZoneProvider.GetDateTimeZone(timezoneId); 

    Assert.AreEqual(expectedTimezoneId, dateTimeZone.Id);
}

Как видите, я ожидаю, что находится в столбце Zone Id (https://nodatime.org/TimeZones), но вместо этого возвращается псевдоним "US / Eastern". Это особенно удивительно, поскольку в документации по GetZoneOrNull (https://nodatime.org/2.4.x/api/NodaTime.IDateTimeZoneProvider.html#NodaTime_IDateTimeZoneProvider_GetZoneOrNull_System_String_) говорится: «Обратите внимание, что при этом может возвращаться DateTimeZone, у которого идентификатор отличается от запрошенного, если указанный идентификатор является псевдонимом».

После прочтения «Обратите также внимание, что этот метод не обязан возвращать один и тот же экземпляр DateTimeZone для последовательных запросов одного и того же идентификатора; однако все экземпляры, возвращаемые для данного идентификатора, должны сравниваться как равные». Я подумал, что, возможно, aliased DateTimeZone будет приравнен к unaliased.

[TestMethod]
public void GetDateTimeZone_DateTimeZoneProviderHasTimezoneIdAsAlias_ReturnsDateTimeZone()
{
    var expectedDateTimeZone = _dateTimeZoneProvider.GetZoneOrNull("America/New_York");
    var timezoneId = "US/Eastern";
    var dateTimeZone = _dateTimeZoneProvider.GetDateTimeZone(timezoneId);

    Assert.AreEqual(expectedDateTimeZone, dateTimeZone);
}

Но это не так. Код, который вызывает метод расширения, на самом деле не заботится об идентификаторе, так как он использует DateTimeZone для преобразования из LocalTime в Ut c.

IDateTimeZoneProvider dateTimeZoneProvider = DateTimeZoneProviders.Tzdb;
var dateTimeZone = dateTimeZoneProvider.GetDateTimeZone(timezoneId);

var zonedDateTime = dateTimeZone.AtLeniently(localDateTime);
return zonedDateTime.ToDateTimeUtc(); 

Таким образом, он будет принимать любое текущее смещение во время localDateTime. Но для целей модульного тестирования я не могу просто проверить смещение, как в примере «America / New_York», потому что иногда оно равно -5, а иногда - -4. Утверждение, что в модульном тесте это либо -5, либо -4, не кажется кошерным. Как мне go проверять псевдоним DateTimeZone?

UPDATE

Вот обновленный модульный тест с указанием c даты и времени, когда смещение известно.

[TestMethod]
public void GetDateTimeZone_DateTimeZoneProviderHasTimezoneIdAsAlias_ReturnsDateTimeZone()
{
    var expectedOffset = Offset.FromHours(-5);
    var specificDateTimeWithKnownUtcOffset = new DateTime(2020, 1, 15, 8, 29, 15, DateTimeKind.Utc);
    var instant = Instant.FromDateTimeUtc(specificDateTimeWithKnownUtcOffset);
    var timezoneId = "US/Eastern";
    var dateTimeZone = _dateTimeZoneProvider.GetDateTimeZone(timezoneId);

    Assert.AreEqual(expectedOffset, dateTimeZone.GetUtcOffset(instant));
}

1 Ответ

3 голосов
/ 15 января 2020

Посмотрев на код, мы можем немного изменить документацию. Текущее поведение TzdbDateTimeZoneSource состоит в том, чтобы возвращать DateTimeZone с запрошенным идентификатором, но он использует данные, связанные с каноническим идентификатором.

Я бы сказал, что это на самом деле не нарушает документированное поведение - это утверждает, что передача псевдонима может предоставить вам зону с каноническим идентификатором вместо этого - но в лучшем случае вводит в заблуждение.

Я бы, вероятно, написал тесты, чтобы они не зависели ни от поведения, ни от зависеть от текущего поведения - которое вряд ли изменится в будущих версиях. (Приятно сохранять переданный идентификатор.) Мне нужно выяснить, есть ли случаи, когда мы действительно хотим вернуть зону с каноническим идентификатором, но я подозреваю мы можно просто сжать документы на 3.0.

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

Обратите внимание, что смещение UT C -4 или UT C -5 не является произвольным - вы могли бы легко напишите тест, который использовал бы указанный c идентификатор часового пояса и местную дату / время, и ожидайте данный момент на основе этого.

...