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()
:
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;