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 !