Aller au contenu principal

2-7-3 Faire une requête authentifiée

Pour tester une requête nécessitant l'autorisation à l'API, essayons de créer un événement via l'API.

  1. Créons la fonction de test Creer_EvenementValide_RetourneOk() dans la classe de test des événements EvenementsTest.

    Snowfall.Tests/Web.Api/TestsIntegration/EvenementsTests.cs
    //...

    [Fact]
    public async Task Creer_EvenementValide_RetourneOk()
    {

    }
  2. Ensuite, préparons les données en créant un DTO et en créant le contexte d'utilisateur connecté via CreerClientUtilisateur.

    Snowfall.Tests/Web.Api/TestsIntegration/EvenementsTests.cs
    [Fact]
    public async Task Creer_EvenementValide_RetourneOk()
    {
    // Arrange
    string url = "api/evenements";
    string courriel = "a@dmin.com";
    var client = await CreerClientUtilisateur(courriel);

    var ville = new Ville()
    {
    Nom = "Paris",
    PaysIso = "fr"
    };
    ville = await VilleRepository.Create(ville);

    var creerEvenementDto = new CreerEvenementDto
    {
    Nom = "Nouvel événement",
    Description = "Description",
    Date = DateTime.Now,
    VilleId = ville.Id,
    Capacite = 300,
    Prix = new Decimal(49.88)
    };
    }
    info

    Remarquez que nous commençons à remarquer une certaine duplication pour l'insertion d'une ville. Il pourrait être pertinent de sortir dans une fonction de la classe du test.

    info

    Ici, je sais que a@dmin.com est un utilisateur possédant le rôle ADMIN puisque dans les seed de BD j'ai fait l'association entre l'utilisateur et le rôle via la table pivot. C'est la seule portion que nous conservons des seeds, sans réinitialiser la BD à chaque occasion

  3. Puis, on effectue la requête à l'aide de PostAsJsonAsync pour ensuite vérifier que le retour est un succès.

    Snowfall.Tests/Web.Api/TestsIntegration/EvenementsTests.cs
    public async Task Creer_EvenementValide_RetourneOk()
    {
    // Arrange
    string url = "api/evenements";
    string courriel = "a@dmin.com";
    var client = await CreerClientUtilisateur(courriel);

    var ville = new Ville()
    {
    Nom = "Paris",
    PaysIso = "fr"
    };
    ville = await VilleRepository.Create(ville);

    var creerEvenementDto = new CreerEvenementDto
    {
    Nom = "Nouvel événement",
    Description = "Description",
    Date = DateTime.Now,
    VilleId = ville.Id,
    Capacite = 300,
    Prix = new Decimal(49.88)
    };

    // Act
    var reponse = await client.PostAsJsonAsync(url, creerEvenementDto);

    // Assert
    Assert.Equal(HttpStatusCode.OK, reponse.StatusCode);
    }
  4. On peut aussi valider qu'un identifiant a bien été assigné et qu'un DTO d'événement est retourné.

    Snowfall.Tests/Web.Api/TestsIntegration/EvenementsTests.cs
    [Fact]
    public async Task Creer_EvenementValide_RetourneOk()
    {
    // Arrange
    string url = "api/evenements";
    string courriel = "a@dmin.com";
    var client = await CreerClientUtilisateur(courriel);

    var ville = new Ville()
    {
    Nom = "Paris",
    PaysIso = "fr"
    };
    ville = await VilleRepository.Create(ville);

    var creerEvenementDto = new CreerEvenementDto
    {
    Nom = "Nouvel événement",
    Description = "Description",
    Date = DateTime.Now,
    VilleId = ville.Id,
    Capacite = 300,
    Prix = new Decimal(49.88)
    };

    // Act
    var reponse = await client.PostAsJsonAsync(url, creerEvenementDto);

    // Assert
    Assert.Equal(HttpStatusCode.OK, reponse.StatusCode);
    var evenementDto = await reponse.Content.ReadFromJsonAsync<EvenementDto>();;
    Assert.NotNull(evenementDto);
    Assert.True(evenementDto.Id > 0);
    Assert.Equal(creerEvenementDto.Nom, evenementDto.Nom);
    }
  5. Finalement, une approche plus simple et plutôt efficace que j'affectionne particulièrement est de vérifier le nombre d'items dans la BD avant l'insertion et après l'insertion. Ainsi, si l'insertion a réussi, la quantité d'items dans la BD aura augmenté de 1. On s'assure ainsi que le contrôleur n'a pas juste retourné un DTO sans faire la sauvegarde en BD.

    Snowfall.Tests/Web.Api/TestsIntegration/EvenementsTests.cs
    [Fact]
    public async Task Creer_EvenementValide_RetourneOk()
    {
    // Arrange
    string url = "api/evenements";
    string courriel = "a@dmin.com";
    var client = await CreerClientUtilisateur(courriel);
    int compteInitial = (await EvenementRepository.GetAll()).Count;

    var ville = new Ville()
    {
    Nom = "Paris",
    PaysIso = "fr"
    };
    ville = await VilleRepository.Create(ville);

    var creerEvenementDto = new CreerEvenementDto
    {
    Nom = "Nouvel événement",
    Description = "Description",
    Date = DateTime.Now,
    VilleId = ville.Id,
    Capacite = 300,
    Prix = new Decimal(49.88)
    };

    // Act
    var reponse = await client.PostAsJsonAsync(url, creerEvenementDto);

    // Assert
    Assert.Equal(HttpStatusCode.OK, reponse.StatusCode);
    var evenementDto = await reponse.Content.ReadFromJsonAsync<EvenementDto>();;
    Assert.NotNull(evenementDto);
    Assert.True(evenementDto.Id > 0);
    Assert.Equal(creerEvenementDto.Nom, evenementDto.Nom);

    int compteFinal = (await EvenementRepository.GetAll()).Count;
    Assert.Equal(compteInitial+1, compteFinal);
    }
  6. Finalement, on peut alléger le test en déléguant à une méthode privée la création du DTO de test.

    Snowfall.Tests/TestsApi/TestsIntegration/EvenementsTests.cs
    public class EvenementsTests : IClassFixture<SnowfallApiApplication>
    {
    //...

    [Fact]
    public async Task Creer_EvenementValide_RetourneOk()
    {
    // Arrange
    using var scope = _application.Services.CreateScope();
    var evenementRepository = scope.ServiceProvider.GetRequiredService<IEvenementRepository>();
    int compteInitial = (await evenementRepository.GetAll()).Count;

    string url = "api/evenements";
    string courriel = "a@dmin.com";
    var client = await _application.CreerClientUtilisateur(courriel);
    var evenementDto = EvenementDto();

    // Act
    var reponse = await client.PostAsJsonAsync(url, evenementDto);
    Assert.Equal(HttpStatusCode.OK, reponse.StatusCode);

    int compteFinal = (await evenementRepository.GetAll()).Count;
    Assert.Equal(compteFinal, compteInitial+1);
    }

    private EvenementDto EvenementDto()
    {
    return new EvenementDto
    {
    Nom = "Nouvel événement",
    Description = "Description",
    Date = DateTime.Now,
    VilleId = 1,
    Capacite = 300,
    Prix = new Decimal(49.88)
    };

    //highlight-end}
    }

Tester un ou des cas invalides

Il est important de tester d'autres cas de figure. Par exemple, que la création n'est pas réussie dans le cas d'un événement non valide.

Par exemple, voici un test similaire, mais adapté pour mettre le nom de l'événement vide et ensuite vérifier que la réponse contient bien des erreurs de validation.

Snowfall.Tests/Web.Api/TestsIntegration/EvenementsTests.cs
[Fact]
public async Task Creer_EvenementNonValide_RetourneErreursValidation()
{
// Arrange
string url = "api/evenements";
string courriel = "a@dmin.com";
var client = await CreerClientUtilisateur(courriel);
int compteInitial = (await EvenementRepository.GetAll()).Count;

var ville = new Ville()
{
Nom = "Paris",
PaysIso = "fr"
};
ville = await VilleRepository.Create(ville);

var creerEvenementDto = new CreerEvenementDto
{
Nom = "",
Description = "Description",
Date = DateTime.Now,
VilleId = ville.Id,
Capacite = 300,
Prix = new Decimal(49.88)
};

// Act
var reponse = await client.PostAsJsonAsync(url, creerEvenementDto);

// Assert
Assert.Equal(HttpStatusCode.BadRequest, reponse.StatusCode);

var problemDetails = await reponse.Content.ReadFromJsonAsync<ValidationProblemDetails>();
Assert.NotNull(problemDetails);
Assert.Equal("One or more validation errors occurred.", problemDetails.Title);
Assert.NotEmpty(problemDetails.Errors);
Assert.Equal(new[] { "Le nom est requis" }, problemDetails.Errors["Nom"]);

int compteFinal = (await EvenementRepository.GetAll()).Count;
Assert.Equal(compteInitial, compteFinal);
}

Réduire la répétition

Remarquez que dans les tests, on crée le même DTO de base. Afin d'éviter la répétition, vous pouvez créer une fonction dans la classe telle que:

Snowfall.Tests/Web.Api/TestsIntegration/EvenementsTests.cs
private async Task<CreerEvenementDto> CreerEvenementDto()
{
var ville = new Ville()
{
Nom = "Paris",
PaysIso = "fr"
};
ville = await VilleRepository.Create(ville);

var creerEvenementDto = new CreerEvenementDto
{
Nom = "Nouvel événement",
Description = "Description",
Date = DateTime.Now,
VilleId = ville.Id,
Capacite = 300,
Prix = new Decimal(49.88)
};

return creerEvenementDto;
}

Cette fonction peut ensuite être utilisée dans les tests de sorte à réduire la répétition.

Snowfall.Tests/Web.Api/TestsIntegration/EvenementsTests.cs
public async Task Creer_EvenementNonValide_RetourneErreursValidation()
{
// Arrange
string url = "api/evenements";
string courriel = "a@dmin.com";
var client = await CreerClientUtilisateur(courriel);
int compteInitial = (await EvenementRepository.GetAll()).Count;

CreerEvenementDto creerEvenementDto = await CreerEvenementDto();
creerEvenementDto.Nom = "";