Bienvenue dans mon blog

Je me présente je m’appelle Pape Singane DIENG. Je suis ingénieur développeur en Informatique passionné par le Software Craftsmanship. C’est la raison pour laquelle j’ai décidé de créer ce blog pour partager avec vous mes expériences. Je vais évoquer dans ce blog différents sujets tels que des méthodes qui permettent d’améliorer la qualité logicielle. J’évoquerai ainsi l’agilité, les pratiques de développements « guidés » par les tests (le TDD, le BDD, le TCR,..), les pratiques de développement en èquipe (Pair Programming, Mob Programming, Code Review), le Continous Integration/Delivery, le Clean Code,…

Bref je parlerai de tous les sujets qui me passionnent.

N’hésitez pas à me faire un feedback pour améliorer les contenus 🙂

Bonne lecture!

Le manifest pour le Software Craftmanship

Faire des tests unitaires modernes avec TUnit

Le paysage des frameworks de tests unitaires en .NET a longtemps été dominé par des frameworks comme xUnit, NUnit ou MSTest. Avec .NET 8/9, un nouveau framework de test moderne TUnit, intégré nativement à l’écosystème .NET permet de faire des tests adaptés à du .Net moderne.

TUnit se distingue par sa syntaxe plus expressive, son intégration transparente avec le SDK .NET, sa rapidité (exécution parallèle) et permet d’avoir un async-first design.

Nous allons voir dans cet article comment utiliser TUnit et, en quoi il représente une évolution naturelle des pratiques de test dans l’univers .NET

Pour commencer avec TUnit

Pour utiliser TUnit il suffit d’installer le package TUnit (nous allons utiliser la version 0.90.6 dans cet article)

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="TUnit" Version="0.90.6" />
  </ItemGroup>
</Project>

En plus d’être un framework d’exécution de tests, TUnit vient avec une librairie assez complète et fluent pour faire des assertions. Quand on utilisait XUnit ou NUnit, on ajoutait en plus un framework pour faire les assertions comme NFluent ou FluentAssertions. TUnit embarque toutes les fonctionnalités de ces framework (en mieux) et toutes les assertions sont async

Voyons dans un premier exemple simple à quoi ressemble TUnit

public class TUnitFirstExampleTest
{
    [Test]
    public async Task Should_Pow_Number()
    {
        var result = Math.Pow(5, 2);
        await Assert.That(result).IsEqualTo(25);
    }

    [Test]
    [Arguments(5, 25)]
    public async Task Should_Pow_Number(int input, int expected)
    {
        var result = Math.Pow(input, 2);
        await Assert.That(result).IsEqualTo(expected);
    }
}

Quelques premières remarques par rapport à la syntaxe et une comparaison par rapport à XUnit

  • Le mot clé pour méthode de test c’est [Test] pour une méthode avec ou sans arguments (pour xunit c’est Fact et Theory/InlineData), la syntaxe est plus lisible/simple.
  • Il n’est pas nécessaire de mettre un using TUnit car c’est détecté automatiquement
  • Les méthodes pour faire assertions : await Assert.That() : c’est similaire à la syntaxe NFluent avec l’ajout du await pour avoir un design async-first (surtout si on fait du TDD) qui est hyper important pour les API modernes.

Utilisation de TUnit pour les collections

Supposons que nous avons une API qui permet de gérer des users avec une entité User et un service UserService

public class User
{
    public int Id { get; set; }
    public required string Name { get; set; }
    public string? Email { get; set; }
}
public interface IUserService
{
    Task<IList<User>> GetAllUsersAsync();
}

public class UserService : IUserService
{
    public async Task<IList<User>> GetAllUsersAsync()
    {
        await Task.Delay(1000); //pour simuler l'appel à une méthode async comme l'accès à la base de données
        IList<User> users =
        [
            new User
            {
                Id = 1,
                Name = "Pape DIENG",
                Email = "tunit@test.fr"
            },
            new User
            {
                Id = 2,
                Name = "Mr Chicken",
                Email = "ChickenIsLife@test.fr"
            }
        ];
        return users;
    }
}

Les collections font partie des objets qui sont très utilisés pour faire des tests unitaire. Ci dessous quelques méthodes d’extensions TUnit qui permettent de faciliter les tests sur les collections

namespace TUnitDemo
{
    public class UserServiceTest
    {
        private readonly IUserService _userService;
        public UserServiceTest()
        {
            _userService = new UserService();
        }

        [Test]
        public async Task Should_Check_TUnit_Collection_Items()
        {
            IList<User> users = await _userService.GetAllUsersAsync();

            //Check sur la non nullité, la taille et exemple d'utilisation de l'opérateur And
            await Assert.That(users).IsNotNull()
                .And.IsNotEmpty()
                .And.HasCount(2);


            //Check qu'un user existe et en plus stockage du résulat dans un objet en une seule instruction
            var pape = await Assert.That(users).Contains(u => u.Id == 1);

            await Assert.That(pape.Name).EqualTo("Pape DIENG");

            //Check sur la non existence
            await Assert.That(users).DoesNotContain(u => u.Id == -1);

            //Check qu'une collection contient un seul élément
            await Assert.That(users.Where(u=>u.Id == 1)).HasSingleItem();

            //Check si une collection est triée
            await Assert.That(users).IsOrderedBy(u => u.Id);

            //Check que tous les Items de la collection vérifient une condition
            await Assert.That(users).All(u => u.Id > 0);


            /*Pour aller plus loin on a :
             * IsEquivalentTo().Using() pour comparer des collections
             * IsNotEquivalentTo()
             * Check sur les collections de collections
             * pour plus d'exemples https://tunit.dev/docs/assertions/collections
             */

        }
    }
}

Comme vous pouvez le voir TUnit offre une librairie très complète et fluent pour manipuler des collections. La librairie contient aussi ce qu’il faut pour manipuler tout type d’objets en .Net :

  • Les types valeurs/références
  • Check sur les Enum
  • Check sur le types : interface, class, types spécifiques, les types primitifs, les objets ORM,…
  • une librairie riche sur les exceptions : type d’exception, message avec ou sans casse, l’inner exception, …
  • Une librairie riche sur les DateTime/DateOnly (IsUtc(), IsInFuture(), IsInPast(),IsInFutureUtc(), IsOnWeekday(), IsOnWeekend(),IsGreater/Less/ThanOrEqualTo() ...) pour plus d’infos sur la librairie spécifique aux dates => https://tunit.dev/docs/assertions/datetime
  • une librairie spécifique sur les dictionnaires

Si vous voulez tester/découvrir toutes les fonctionnalités que propose TUnit, vous aurez toutes les informations ici https://tunit.dev/docs/assertions/getting-started

Conclusion

Etant quelqu’un qui est passionné par les tests (unitaires, d’intégration, end to end, BDD, …) et particulièrement tout ce qui est « test driven », j’ai été séduit par le framework TUnit. Au cours des presque 10 dernières années, j’ai fait la promotion de XUnit/NFluent au sein des équipes où j’ai travaillé, et maintenant, pour les tests, je recommande fortement TUnit pour les projets modernes en .Net 8+, surtout pour les API. J’espère que ça vous motivera à le tester même si XUnit est encore plus répandu à ce jour avec une grande communauté 🙂

Faire des tests élégants et efficaces avec NFluent

Je voulais écrire un article sur NFluent car c’est un Framework dont je suis particulièrement fan (car TDD friendly) et que j’utilise depuis plus de 4 ans car il permet d’écrire des tests plus « clean ». Généralement un test (unitaire, intégration, BDD,…) est composé de 3 parties: Arrange, Act, Assert (la règle des 3A). NFluent permet d’écrire les assertions des tests d’une manière plus « Fluent » et donc plus lisible.

Lire la suite »

Software Craftsmanship: How to build well crafted software?

In his book The Software Craftsman: Professionalism, Pragmatism, Pride, Sandro Mancuso said « Software Craftsmanship is a long journey to mastery. It’s a mindset where software developers choose to be responsible for their own careers, constantly learning new tools and techniques and constantly bettering themselves. » As a Software Craftsman I wanted to share with you some techniques/practises that really worked well with my teams and that enable to constantly improve code quality and motivate people. In the article, I’ll talk about what it is to be agile, about TDD, BDD, XP (Pair Programming, Mob Programming, …), Continuous Integration / Delivery, Clean Code,…

Lire la suite »