Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Un « projet zéro » MAUI réaliste partie 2/5 – Les tests unitaires

Plus loin qu’un simple Hello World je vous propose en 5 articles / cours de créer un « projet zéro » réaliste. Aujourd’hui les tests unitaires sont au programme !

Cet article fait partie d’une série de 5 épisodes dont voici les liens (apparaissant au fur et à mesure des parutions au début de chaque article) :
1- https://www.e-naxos.com/Blog/post/un-projet-zero-maui-realiste-partie-1-5-creation-du-projet-et-mvvm.aspx (Création du projet et MVVM)
2 - https://www.e-naxos.com/Blog/post/un-projet-zero-maui-realiste-partie-2-5-les-tests-unitaires.aspx (Les tests unitaires)

Un Hello World réaliste

Dans l’article précédent je vous ai montré comment créer le projet de base et lui ajouter la logique MVVM afin de le structurer de façon propre et réaliste, c’est-à-dire de la façon dont on procède dans la « vraie vie » ce que ne fait pas le Hello World présenté il y a quelques semaines.

Les Tests Unitaires

Les tests unitaires (Unit Testing en anglais) sont à la base d’une programmation efficace, contrôlée et même maîtrisée. Dans les faits beaucoup de développeurs s’en passent, à tort, mais à leur décharge le temps (le budget) ne leur est souvent pas donné pour accomplir cette tâche essentielle. Une majorité en a conscience, mais une partie continue de croire qu’on peut créer une App sans des tests rigoureux assurant la non régression du code autant que la validité de chaque partie essentielle. C’est très dommage et je les encourage à se questionner et à s’intéresser à cette pratique que nous allons mettre en évidence sur notre projet de base.

Bien entendu les tests d’une App concernent tout autant l’UI et l’UX que le code. Toutefois ici je me focaliserais uniquement sur les tests du code C#. C’est déjà beaucoup ! Mais sachez qu’il existe aussi des toolkits pour tester les UI et qu’il est fort utile de savoir les manipuler (pour les mêmes raisons que les tests de code : par exemple vérifier que l’appui sur tel bouton déclenche bien telle action et que tel label est bien mis à jour. Essentiel bien entendu).

Certaines méthodes de développement découlent même des tests qui sont écrits en premier (TDD) même si comme toutes les méthodes elles sont restées confidentielles car elles oublient toutes qu’un logiciel n’est pas une question de techniques de spécialistes mais bien un objet destiné à des humains avec qui il faut garder le contact (compassion, aide, compréhension, qui imposent lisibilité, accessibilité, inclusivité, bon sens…).

Bref, le monde des tests c’est vaste, cela a des implications sur les coûts de fabrication mais diminue la dette technique et assure une meilleure longévité des applications.

Ici, concentrons-nous sur l’aspect purement pratique et mettons en œuvre des tests unitaires pour contrôler le code du projet zéro que nous avons construit et enrichi avec MVVM.

xUnit

Ce framework / toolkit de test est très utilisé dans le monde Xamarin.Forms et il n’y a aucune raison de ne pas s’en servir sous MAUI !

En voici en quelques mots la présentation qui en est faite sur leur site https://xunit.net/ :

« xUnit.net est un outil de test unitaire gratuit, open source et axé sur la communauté pour le .NET Framework. Écrit par l'inventeur original de NUnit v2, xUnit.net est la dernière technologie pour les tests unitaires C#, F#, VB.NET et d'autres langages .NET. xUnit.net fonctionne avec ReSharper, CodeRush, TestDriven.NET et Xamarin. Il fait partie de la Fondation .NET et opère selon leur code de conduite . Il est sous licence Apache 2 (une licence approuvée par l'OSI). »

Voilà pour les présentations. Passons à l’action.

Ajouter un projet de test xUnit

Il suffit pour le moment de faire un clic droit sur la solution et d’ajouter un nouveau projet et de choisir xUnit ce que vous saurez faire sans problème :

Oune project qué s’apélerio point Quesac mais RealisticHelloWorld.Tests, du nom du projet que j’ai créé au départ, mettez ce que vous voulez bien entendu.

Ce projet est aujourd’hui créé par défaut en .NET 6, demain en 7 puis en 8 etc. Ce qui compte c’est que cela soit raccord avec votre App.

Compilons ce nouveau « projet de base » orienté tests pour voir ce que cela donne.

Une fois le projet généré pour contrôler qu’il se compile bien, ouvrons le menu Visual Studio « Test » puis « Exécuter tous les tests ». la fenêtre de l’explorateur de test va s’ouvrir et nous y verrons ceci :

Le « Test1 » est le test par défaut intégré au projet qu’on vient de créer, il ne fait rien puisque le projet de test n’est relié à aucun projet à tester… Mais c’est rassurant de voir que cela fonctionne. Ne reste plus qu’à ajouter dans ses dépendances le projet MAUI puis à écrire quelques tests.

Mais… mais ce n’est pas aussi direct. Ajoutons juste la dépendance au projet MAUI et sans rien toucher d’autre essayons d’exécuter à nouveau les tests…

Pas la peine d’essayer, à peine la dépendance ajoutée des messages d’erreurs apparaissent :

Bon, certains ont pataugé longtemps, ce n’est pas évident. Le problème c’est qu’il faut lire les messages d’erreur… Et que nous disent-ils ? Que notre projet MAUI n’est pas compatible avec .NET 6. Tout bêtement… Il suffit donc d’ajouter cette cible à notre projet MAUI. En effet xUnit teste du code .NET, pas du code Android ou iOS qu’il ne connait pas. Et si vous regardez le projet MAUI il a plus frameworks cibles mais pas .NET 6 tout court…

Cela semble donc simple à résoudre. Mais en fait pas tant que ça. Le système de test n’aime pas du tout l’exe créé par MAUI, il faudrait lui fournir une DLL ! Là c’est plus embêtant. Certains on a réussi à contourner le problème en créant une DLL MAUI qui contient tout le code des ViewModels par exemple, ce qui fonctionne mais complique inutilement les choses (un projet de plus, du code à balader d’un point à un autre, puis ensuite travailler sur deux projets, la DLL quand on ajoute ou modifie un ViewModel et l’exe MAUI pour tout le reste).

C’est vrai que ce n’est pas si évident à contourner et pourtant…

Reprenons.

Si vous éditez le csproj du projet MAUI vous verrez ceci :

Il s’agit de la cible TargetFrameworks. On y trouve tout sauf du .NET 6 pur « de base ». Ajoutons-le !

Ce qui donne (regardez le début de la balise) :

J’ai ajouté « net6.0 ; » en début de balise.

Mais ce n’est pas tout puisqu’il faut que la sortie soit une DLL et non un Exe MAUI. Diable ! Bon, si vous ne connaissez pas bien MS Build vous pouvez toujours vous inspirer d’autres lignes de configuration plus bas dans le csproj. Il est possible de placer des conditions dans les balises. Pour faire simple (car MS Build est encore un sujet qui mériterait un livre !) nous allons faire en sorte que lorsque le projet est compilé depuis le projet de test il produise une DLL, sinon un EXE.

Juste en dessous des frameworks cibles, on trouve :

Voici ce que nous allons mettre à la place :

Le principe est simple, si la cible est .NET 6 (quand la compilation a lieu depuis le programme de test) le test va échouer, et le mode de sortie Exe sera ignoré. Or, par défaut, si rien n’est spécifié, c’est le mode DLL qui est appliqué ! Tout juste ce dont le projet de test a besoin…

Mais cela risque de ne pas marcher du premier coup en raison du changement de type du projet et sa nouvelle balise conditionnelle. Le mieux, maintenant que la situation a été corrigée, est de sortir de VS, faire le propre dans les projets (supprimer bin et obj) et de revenir dans VS.

Ajouter des tests

On dispose maintenant d’un projet de test qui fonctionne parfaitement, en tout cas qui compile tout en ayant une référence sur notre projet MAUI qui sait maintenant produire une DLL sous test et un Exe le reste du temps.

Mais tout cela ne sert à rien si nous n’ajoutons pas quelques tests afin de prouver que cela fonctionne vraiment !

Supprimons au passage le fichier UnitTest1.cs qui est apporté par le projet de test par défaut. Et ajoutons la classe suivante (dans son fichier propre bien entendu) :

using
RealisticHelloWorld.ViewModels;
namespace RealisticHellowWord.Tests;
 
public class CounterTest
{
    [Fact]
    public void Increment_counter_by_one_using_command()
    {
        // prepare test
        int expected = 1;
        var vm = new Counter();
 
        // verify the starting count
        Assert.True(vm.Count == 0, "Starting count should have been zero.");
 
        // act
        vm.IncreaseCounterCommand.Execute(null);
 
        // Verify count final value
        Assert.Equal(expected, vm.Count);
    }
}

Clic droit sur le test dans l’explorateur de tests, puis Exécuter.  Et le test doit passer sans souci :

Conclusion de la partie 2/5

Nous sommes allés déjà assez loin en partant du Hello World de base ! Support de MVVM et maintenant tests unitaires plus les astuces pour les faire fonctionner sous MAUI… Deux longs articles pleins de bonnes choses ! Mais il ne faut pas abuser de ces dernières, c’est bien connu, alors il est temps de clore le présent article. Pour mieux revenir sur d’autres aspects dans les 3 prochains épisodes !

Stay Tuned !

Faites des heureux, partagez l'article !
blog comments powered by Disqus