Модульное тестирование с контекстом базы данных сущности: не сбрасывает счетчик идентификаторов - PullRequest
0 голосов
/ 15 марта 2019

Я пытаюсь написать модульное тестирование довольно простого веб-сервиса на основе ядра ASP.Net. Для сохранения я использую ядро ​​Entity Framework для доступа к базе данных SQL.

В модульных тестах мне явно не нужна база данных, которая могла бы перетекать из одного теста в другой. После некоторых поисков я нашел эту статью https://docs.microsoft.com/en-us/ef/core/miscellaneous/testing/in-memory. Мой тестовый код теперь выглядит примерно так:

[Fact]
public void Test_method()
{    
    var options = new DbContextOptionsBuilder<ServiceContext>()
        .UseInMemoryDatabase(databaseName: "Test_method") // Unique name for each test
        .Options;

    using (var context = new ServiceContext(options))
    {
        // Add test data
        context.Dataset.Add(new ...);
        context.SaveChanges();
    }

    using (var context = new ServiceContext(options))
    {
        // Perform tests
        var controller = new Controller(new Service(context));
        ...
    }
}

Это почти работает, каждый тестовый пример начинается с пустой БД. Но идентификаторы, которые присваиваются элементам testdata, не сбрасываются. Поэтому, если у меня есть один тест, который добавляет один элемент в свою БД, и другой тест, который добавляет два, тестовый элемент в первом тесте может получить идентификатор 1 или 3, в зависимости от порядка выполнения этих двух тестов.

Есть ли способ убедиться, что идентификаторы всегда начинаются с 1 в одном методе тестирования? Тестирование кода, который выполняет поиск на основе идентификаторов, действительно довольно уродливо, когда идентификаторы зависят от того, выполнялись ли другие тесты до текущего.

Ответы [ 2 ]

1 голос
/ 15 марта 2019

Entity Framework inmemory database не сбрасывает счетчик автоинкрементов.

Вот заявление из выпуска Github:

The InMemory provider doesn't the Identity pattern you would get in a relational database. When a column is configured as ValueGeneratedOnAdd it uses values from a single generator for all tables. This would be similar to having all tables setup to use a single sequence in a relational database. This raises one of the important design principles of our InMemory provider, which is that we are not trying to emulate a relational database. This becomes more important as we start to light up non-relational providers.

If you want to have a database that acts like a relational database, but doesn't have the overhead of I/O, then we'd recommend using an In-Memory SQLite database - http://www.sqlite.org/inmemorydb.html.

We're going to update our testing docs to make the SQLite option more prominent.

Источник: https://github.com/aspnet/EntityFrameworkCore/issues/6872

Так что вы можете подумать о том, чтобы сбросить счетчик вручную при каждом запуске теста (что-то вроде ALTER TABLE mytable AUTO_INCREMENT = 1;), или использовать другого поставщика sql, как упомянуто в посте.

0 голосов
/ 15 марта 2019

Просто используйте что-нибудь случайное в качестве имени вашей базы данных, например Guid.NewGuid().ToString(), которое будет сбрасывать все, каждый раз, потому что это будет совершенно новая «база данных» в памяти.

var options = new DbContextOptionsBuilder<ServiceContext>()
    .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) // Unique name for each test
    .Options;
...