Как написать интеграционные тесты с использованием сериализации DateTime Json в ASP.NET Core 3.0? - PullRequest
0 голосов
/ 06 ноября 2019

Я пишу интеграционный тест для контроллера Api в ASP.NET Core 3.0. Тест для маршрута, который отвечает со списком объектов. Когда я пытаюсь сделать утверждения для содержимого ответа, существует расхождение в способе сериализации свойств DateTime.

Я пытался использовать в тесте пользовательский JsonConverter:

    public class DateTimeConverter : JsonConverter<DateTime>
    {
        public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            return DateTime.Parse(reader.GetString());
        }

        public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString("yyyy-MM-ddThh:mm:ss.ffffff"));
        }
    }

Проблема в том, что этот преобразователь не усекает конечные нули, в то время как фактический ответ делает. Итак, у теста есть шанс 1 к 10. Неудачный.

Это неудачный тест:

    [Fact]
    public async Task GetUsers()
    {
        using var clientFactory = new ApplicationFactory<Startup>();
        using var client = clientFactory.CreateClient();
        using var context = clientFactory.CreateContext();

        var user1 = context.Users.Add(new User()).Entity;
        var user2 = context.Users.Add(new User()).Entity;
        context.SaveChanges();

        var users = new List<User> { user1, user2 };
        var jsonSerializerOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };
        var serializedUsers = JsonSerializer.Serialize(users, jsonSerializerOptions);

        var response = await client.GetAsync("/users");

        var responseBody = await response.Content.ReadAsStringAsync();
        Assert.Equal(serializedUsers, responseBody);
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    }

Я ожидал, что тест пройден, но вместо этого я получаю эту ошибку:

  Error Message:
   Assert.Equal() Failure
                                 ↓ (pos 85)
Expected: ···1-05T22:14:13.242771-03:00","updatedAt"···
Actual:   ···1-05T22:14:13.242771","updatedAt"···

Я не настраивал никакие параметры сериализации в реальной реализации контроллера.

Как правильно реализовать этот интеграционный тест? Есть ли простой способ сериализации списка в тесте, используя те же параметры реального контроллера?

Ответы [ 2 ]

0 голосов
/ 06 ноября 2019

Что вы хотите сделать, это получить представление DateTime «туда-обратно», это можно сделать с помощью:

https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings#Roundtrip

var d = DateTime.Now.ToString("o");

Если проблемы все еще не устраненыделая оба формата DateTime одинаковыми, вы можете использовать свойство «System.DateTime.Kind».

https://docs.microsoft.com/en-us/dotnet/api/system.datetime.kind?view=netframework-4.8

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

https://dotnetfiddle.net/ccGSEO

0 голосов
/ 06 ноября 2019

1. Используйте метки времени UTC

. Я настоятельно рекомендую вам сохранять метки времени в UTC.

var x = new { UpdatedAtUtc = DateTime.UtcNow };

Console.WriteLine(JsonSerializer.Serialize(x));

производит

{"UpdatedAtUtc":"2019-11-06T02:41:45.4610928Z"}

2. Используйте свой конвертер

var x = new { UpdatedAt = DateTime.Now };

JsonSerializerOptions options = new JsonSerializerOptions();
options.Converters.Add(new DateTimeConverter());

Console.WriteLine(JsonSerializer.Serialize(x, options));
{"UpdatedAt":"2019-11-06T12:50:48.711255"}

3. Использование DateTimeKind.Unspecified

class X { public DateTime UpdatedAt {get;set;}}

public static void Main()
{
    var localNow = DateTime.Now;
    var x = new X{ UpdatedAt = localNow };

    Console.WriteLine(JsonSerializer.Serialize(x));
    x.UpdatedAt = DateTime.SpecifyKind(localNow, DateTimeKind.Unspecified);
    Console.WriteLine(JsonSerializer.Serialize(x));

производит

{"UpdatedAt":"2019-11-06T12:33:56.2598121+10:00"}
{"UpdatedAt":"2019-11-06T12:33:56.2598121"}

Кстати. Вы должны использовать те же параметры Json в тестируемом и тестируемом коде.


Примечание по микросекундам и DateTimeKind

По мере тестирования вы можете обнаружить несоответствия по меткам времени между объектамичто вы положили в базу данных и их эквиваленты получены из базы данных.

В зависимости от ваших настроек DateTime s может быть получено из БД как Local или Unspecified (даже если вы добавили Utc в БД), и вы можете потерять часть точности (столбец БДбудет хранить только то, что является максимальным разрешением, это может быть миллисекундами).

...