Aller au contenu principal

4-3 Configuration des serveurs de test

Comme mentionné en introduction, les tests d'intégration utilisaient un serveur en mémoire, c'est-à-dire qu'il n'est pas réellement accessible de l'extérieur. Playwright nécessite que l'application soit exécutée normalement afin qu'un navigateur externe puisse y accéder.

Pour ce faire, il est nécessaire de configurer des serveurs de test pouvant être lancés par les tests xUnit Playwright.

Configuration pour les tests E2E MVC

Créer SnowfallMvcKestrelApplicationFactory

Comme Playwright doit ouvrir un vrai navigateur, il a besoin d'une instance accessible de l'application sur un "vrai" port. Kestrel est le serveur HTTP intégré et par défaut d'ASP .NET Core, il faut donc partir manuellement une instance de ce serveur.

  1. Sous Snowfall.Tests/Web.Mvc -> Add -> Class/Interface
  2. Nommer la classe SnowfallMvcApplicationServeurTest
  3. Faites hériter la classe de SnowfallMvcApplicationFactory
    Snowfall.Tests/Web.Mvc/SnowfallMvcKestrelApplicationFactory.cs
    public class SnowfallMvcKestrelApplicationFactory : SnowfallMvcApplicationFactory
    {

    }
  4. Faites en sorte que cette dernière hérite de la classe WebMvcIntegrationTestBase
    Snowfall.Tests/Web.Mvc/SnowfallMvcApplicationServeurTest.cs
    public class SnowfallMvcApplicationServeurTest : WebMvcIntegrationTestBase
    {
    public SnowfallMvcApplicationServeurTest(
    SnowfallMvcApplicationFactory application,
    TestDatabaseFixture database) : base(application, database)
    {
    }
    }
  5. Mettre le code suivant dans la classe pour construire et démarrer un serveur de test:
    Snowfall.Tests/TestsMvc/SnowfallMvcApplicationServeurTest.cs
    public class SnowfallMvcKestrelApplicationFactory : SnowfallMvcApplicationFactory
    {
    private IHost? _host;

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
    builder.UseEnvironment("Test")
    .UseUrls("http://127.0.0.1:0");
    }

    protected override IHost CreateHost(IHostBuilder builder)
    {
    // Construit le serveur de test en mémoire (requis)
    var testHost = builder.Build();

    // Configure et construit le serveur Kestrel
    builder.ConfigureWebHost(web => web.UseKestrel());
    _host = builder.Build();
    _host.Start();

    // Récupère l'adresse du serveur Kestrel
    var server = _host.Services.GetRequiredService<IServer>();
    var address = server.Features.Get<IServerAddressesFeature>()
    .Addresses.Last();

    // Assigne comme adresse de base celle du serveur Kestrel
    ClientOptions.BaseAddress = new Uri(address);

    // Démarre le serveur de test
    testHost.Start();
    return testHost;
    }

    protected override void Dispose(bool disposing)
    {
    base.Dispose(disposing);
    if (disposing)
    {
    _host?.StopAsync().GetAwaiter().GetResult();
    _host?.Dispose();
    }
    }
    }

Créer WebMvcE2ETestBase

Cette classe servira de base pour les tests. Elle servira entre autres à réinitialiser la base de données à chaque exécution de test, tout comme les tests d'intégration MVC et d'API.

Snowfall.Tests/Web.Mvc/TestsE2E/WebMvcE2ETestBase.cs
public abstract class WebMvcE2ETestBase : IClassFixture<SnowfallMvcKestrelApplicationFactory>, IClassFixture<TestDatabaseFixture>, IAsyncLifetime, IDisposable
{
protected readonly SnowfallMvcKestrelApplicationFactory Application;
protected readonly TestDatabaseFixture Database;
protected IPage Page { get; private set; } = null!;
protected readonly IVilleRepository VilleRepository;
protected readonly IEvenementRepository EvenementRepository;

private IBrowser? _browser;
private readonly IServiceScope _scope;

protected WebMvcE2ETestBase(SnowfallMvcKestrelApplicationFactory application, TestDatabaseFixture database)
{
Application = application;
Database = database;

_scope = Application.Services.CreateScope();
VilleRepository = _scope.ServiceProvider.GetRequiredService<IVilleRepository>();
EvenementRepository = _scope.ServiceProvider.GetRequiredService<IEvenementRepository>();
}

public async Task InitializeAsync()
{
// Réinitialise la base de données
await Database.ResetDatabaseAsync();

// Démarre le serveur
var client = Application.CreateClient();

// Lance Playwright et crée une nouvelle page
var playwright = await Playwright.CreateAsync();
_browser = await playwright.Chromium.LaunchAsync(new
BrowserTypeLaunchOptions
{
Headless = false

});
var context = await _browser.NewContextAsync();
Page = await context.NewPageAsync();
}

public async Task DisposeAsync()
{
if (_browser is not null)
await _browser.CloseAsync();
}

public void Dispose()
{
}
}

Configuration pour les tests E2E API

Créer SnowfallApiKestrelApplicationFactory

attention

Blazor et le serveur Kestrel fonctionnent mal avec l'environnement Test. C'est pourquoi nous allons démarrer le projet normalement en environnement Development, mais allons forcer la récupération de appsettings.Test.json pour que la bd utilisée soit celle de test!

  1. Sous Snowfall.Tests/Web.Api -> Add -> Class/Interface
  2. Nommer la classe SnowfallApiKestrelApplicationFactory
  3. Utilisez un code similaire à MVC, mais légèrement différent puisque la façon de partir l'API n'est pas tout à fait la même.
    Snowfall.Tests/Web.Api/SnowfallApiKestrelApplicationFactory.cs
    public class SnowfallApiKestrelApplicationFactory : WebApplicationFactory<Program>
    {
    private IHost? _host;

    protected override IHost CreateHost(IHostBuilder builder)
    {
    // Force l'utilisation de la configuration de test
    builder.ConfigureAppConfiguration((hostingContext, config) =>
    {
    config.AddJsonFile(
    "appsettings.Test.json",
    optional: true,
    reloadOnChange: false);
    });

    var testHost = builder.Build();

    // Configure le vrai serveur Kestrel
    builder.ConfigureWebHost(web => web.UseKestrel());
    _host = builder.Build();
    _host.Start();

    // Alloue un port aléatoire à Kestrel
    var server = _host.Services.GetRequiredService<IServer>();
    var address = server.Features.Get<IServerAddressesFeature>()!
    .Addresses.Last();

    // Faire pointer l'adresse de base vers celle de Kestrel
    ClientOptions.BaseAddress = new Uri(address);

    // Démarrer le serveur de test
    testHost.Start();

    return testHost;
    }

    protected override void Dispose(bool disposing)
    {
    base.Dispose(disposing);
    if (disposing)
    {
    if (_host is not null)
    {
    _host.StopAsync().GetAwaiter().GetResult();
    _host.Dispose();
    }
    }
    }
    }

Créer WebApiE2ETestBase

Cette classe servira de base pour les tests. Elle servira entre autres à réinitialiser la base de données à chaque exécution de test, tout comme les tests d'intégration MVC et d'API.

  1. Sous le dossier Snowfall.Tests/Web.Api/TestsE2E, créez la classe WebApiE2ETestBase
  2. Mettez-y le code suivant
    Snowfall.Tests/Web.Api/TestsE2E/WebApiE2ETestBase.cs
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Playwright;
    using Snowfall.Data.Repositories;

    namespace Snowfall.Tests.Web.Api.TestsE2E;

    [Collection("Test Database Collection")]
    public abstract class WebApiE2ETestBase : IClassFixture<SnowfallApiKestrelApplicationFactory>, IClassFixture<TestDatabaseFixture>, IAsyncLifetime, IDisposable
    {
    protected readonly SnowfallApiKestrelApplicationFactory Application;
    protected readonly TestDatabaseFixture Database;
    protected IPage Page { get; private set; } = null!;
    protected readonly IVilleRepository VilleRepository;
    protected readonly IEvenementRepository EvenementRepository;

    private IBrowser? _browser;
    private readonly IServiceScope _scope;

    protected WebApiE2ETestBase(SnowfallApiKestrelApplicationFactory application, TestDatabaseFixture database)
    {
    Application = application;
    Database = database;

    _scope = Application.Services.CreateScope();
    VilleRepository = _scope.ServiceProvider.GetRequiredService<IVilleRepository>();
    EvenementRepository = _scope.ServiceProvider.GetRequiredService<IEvenementRepository>();
    }

    public async Task InitializeAsync()
    {
    // Réinitialise la base de données
    await Database.ResetDatabaseAsync();

    // Démarre le serveur
    var client = Application.CreateClient();

    // Lance Playwright et crée une nouvelle page
    var playwright = await Playwright.CreateAsync();
    _browser = await playwright.Chromium.LaunchAsync(new
    BrowserTypeLaunchOptions
    {
    Headless = false

    });
    var context = await _browser.NewContextAsync();
    Page = await context.NewPageAsync();
    }

    public async Task DisposeAsync()
    {
    if (_browser is not null)
    await _browser.CloseAsync();
    }

    public void Dispose()
    {
    }
    }