protected void ExecuteInATransaction(Action actionToExecute)
{
var strategy = Context.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
using var trans = Context.Database.BeginTransaction();
actionToExecute();
trans.Rollback();
});
}
protected void ExecuteInASharedTransaction(Action<IDbContextTransaction>
actionToExecute)
{
var strategy = Context.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
using IDbContextTransaction trans =
Context.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
actionToExecute(trans);
trans.Rollback();
});
}
Добавление класса тестовой оснастки EnsureAutoLotDatabase
Инфраструктура тестирования xUnit предоставляет механизм, который позволяет запускать код до прогона любого теста (называется настройкой оснастки) и после прогона всех тестов (называется освобождением оснастки). Обычно поступать так не рекомендуется, но в рассматриваемом случае желательно удостовериться, что база данных создана и загружена данными до прогона любого теста, а не до прогона каждого теста. Классы тестов, которые реализуют IClassFixture<T> where Т: TestFixtureClass, должны будут выполнять код конструктора типа Т (т.е. TestFixtureClass) до прогона любого теста и код метода Dispose() после завершения всех тестов.
Создайте в каталоге Base новый файл класса по имени EnsureAutoLotDatabaseTestFixture.cs и реализуйте интерфейс IDisposable. Сделайте класс открытым и запечатанным, а также добавьте показанные далее операторы using:
using System;
using AutoLot.Dal.Initialization;
namespace AutoLot.Dal.Tests.Base
{
public sealed class EnsureAutoLotDatabaseTestFixture : IDisposable
{
}
}
В конструкторе понадобится создать экземпляр реализации IConfiguration и с его помощью создать экземпляр ApplicationDbContext. Затем нужно вызвать метод ClearAndReseedDatabase() класса SampleDatalnitializer и в заключение освободить экземпляр контекста. В приводимых здесь примерах метод Dispose() не обязан выполнять какую-то работу (но должен присутствовать для соответствия шаблону с интерфейсом IDisposable). Вот как выглядит конструктор и метод Dispose():
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})
public EnsureAutoLotDatabaseTestFixture()
{
var configuration = TestHelpers.GetConfiguration();
var context = TestHelpers.GetContext(configuration);
SampleDataInitializer.ClearAndReseedDatabase(context);
context.Dispose();
}
public void Dispose()
{
}
Добавление классов интеграционных тестов
Теперь необходимо создать классы, которые будут поддерживать автоматизированные тесты. Такие классы называют тестовыми оснастками. Добавьте в проект AutoLot.Dal. Tests новый каталог по имени IntegrationTests и поместите в него четыре файла с именами CarTests.cs, CustomerTests.cs, MakeTests.cs и OrderTests.cs.
В зависимости от возможностей средства запуска тестов тесты xUnit выполняются последовательно внутри тестовой оснастки (класса), но параллельно во всех тестовых оснастках (классах). Это может оказаться проблематичным при прогоне интеграционных тестов, взаимодействующих с единственной базой данных. Выполнение можно сделать последовательным для всех тестовых оснасток, добавив их в одну и ту же тестовую коллекцию. Тестовые коллекции определяются по имени с применением атрибута [Collection] к классу. Поместите перед всеми четырьмя классами следующий атрибут [Collection]:
[Collection("Integration Tests")]
Унаследуйте все четыре класса от BaseTest, реализуйте интерфейс IClassFixture и приведите операторы using к показанному далее виду:
// CarTests.cs
using System.Collections.Generic;
using System.Linq;
using AutoLot.Dal.Exceptions;
using AutoLot.Dal.Repos;
using AutoLot.Dal.Tests.Base;
using AutoLot.Models.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Storage;
using Xunit;