Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
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;
namespace AutoLot.Dal.Tests.IntegrationTests
{
[Collection("Integation Tests")]
public class CarTests : BaseTest,
IClassFixture<EnsureAutoLotDatabaseTestFixture>
{
}
}
// CustomerTests.cs
using System.Collections.Generic;
using System;
using System.Linq;
using System.Linq.Expressions;
using AutoLot.Dal.Tests.Base;
using AutoLot.Models.Entities;
using Microsoft.EntityFrameworkCore;
using Xunit;
namespace AutoLot.Dal.Tests.IntegrationTests
{
[Collection("Integation Tests")]
public class CustomerTests : BaseTest,
IClassFixture<EnsureAutoLotDatabaseTestFixture>
{
}
}
// MakeTests.cs
using System.Linq;
using AutoLot.Dal.Repos;
using AutoLot.Dal.Repos.Interfaces;
using AutoLot.Dal.Tests.Base;
using AutoLot.Models.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Xunit;
namespace AutoLot.Dal.Tests.IntegrationTests
{
[Collection("Integation Tests")]
public class MakeTests : BaseTest,
IClassFixture<EnsureAutoLotDatabaseTestFixture>
{
}
}
// OrderTests.cs
using System.Linq;
using AutoLot.Dal.Repos;
using AutoLot.Dal.Repos.Interfaces;
using AutoLot.Dal.Tests.Base;
using Microsoft.EntityFrameworkCore;
using Xunit;
namespace AutoLot.Dal.Tests.IntegrationTests
{
[Collection("Integation Tests")]
public class OrderTests : BaseTest,
IClassFixture<EnsureAutoLotDatabaseTestFixture>
{
}
}
Добавьте в класс MakeTests конструктор, который создает экземпляр MakeRepo и присваивает его закрытой переменной readonly уровня класса. Переопределите метод Dispose() и освободите в нем экземпляр MakeRepo:
[Collection("Integration Tests")]
public class MakeTests : BaseTest,
IClassFixture<EnsureAutoLotDatabaseTestFixture>
{
private readonly IMakeRepo _repo;
public MakeTests()
{
_repo = new MakeRepo(Context);
}
public override void Dispose()
{
_repo.Dispose();
}
...
}
Повторите те же действия для класса OrderTests, но с использованием OrderRepo вместо MakeRepo:
[Collection("Integration Tests")]
public class OrderTests : BaseTest,
IClassFixture<EnsureAutoLotDatabaseTestFixture>
{
private readonly IOrderRepo _repo;
public OrderTests()
{
_repo = new OrderRepo(Context);
}
public override void Dispose()
{
_repo.Dispose();
}
...
}
Тестовые методы [Fact] и [Theory]
Тестовые методы без параметров называются фактами (и задействуют атрибут [Fact]). Тестовые методы, которые принимают параметры, называются теориями (они используют атрибут [Theory]) и могут выполнять множество итераций с разными значениями, передаваемыми в качестве параметров. Чтобы взглянуть на такие виды тестов, создайте в проекте AutoLot.Dal.Tests новый файл класса по имени SampleTests.cs. Вот как выглядит оператор using:
using Xunit;
namespace AutoLot.Dal.Tests
{
public class SampleTests
{
}
}
Начните с создания теста [Fact]. В тесте [Fact] все значения содержатся внутри тестового метода. Следующий простой пример проверяет, что 3 + 2 = 5:
[Fact]
public void SimpleFactTest()
{
Assert.Equal(5,3+2);
}
Что касается теста [Theory], то значения передаются тестовому методу и могут поступать из атрибута [InlineData], методов или классов. Здесь будет использоваться только атрибут [InlineData]. Создайте показанный ниже тест, которому предоставляются разные слагаемые и ожидаемый результат:
[Theory]
[InlineData(3,2,5)]
[InlineData(1,-1,0)]
public void SimpleTheoryTest(int addend1, int addend2, int expectedResult)
{
Assert.Equal(expectedResult,addend1+addend2);
}
На заметку! За дополнительными сведениями об инфраструктуре тестирования xUnit обращайтесь в документацию по ссылке https://xunit.net/.
Выполнение тестов
Хотя тесты xUnit можно запускать из командной строки (с применением dotnet test), разработчикам лучше использовать для этого Visual Studio. Выберите в меню Test (Тестирование) пункт Test Explorer (Проводник тестов), чтобы получить возможность прогонять и отлаживать все или выбранные тесты.
Запрашивание базы данных
Вспомните, что создание экземпляров сущностей из базы данных обычно предусматривает выполнение оператора LINQ в отношении свойств DbSet<T>. Поставщик баз данных и механизм трансляции LINQ преобразуют операторы LINQ в запросы SQL, с помощью которых из базы данных читаются соответствующие данные. Данные можно также загружать посредством метода FromSqlRaw()