Skip to content

Tests .NET ​

Cinq projets xUnit, un par périmètre. Les tests du frontend vivent ailleurs : specs Vitest co-localisées dans vue/src/ et scénarios Playwright dans vue/e2e/ — voir le README du frontend.

ProjetCibleFichiersMéthodes de testCe qu'il éprouve
backendnet9.01551263Le service : domaine, services métier, transport Modbus, contrôleurs, chaînes d'intégration — README
clientnet9.0-windows522Vérification de licence, empreinte poste, détection de débogueur, hôte virtuel WebView2 — README
managernet9.0-windows17Chargement de app.config.json par le gestionnaire de service
simulatornet9.0318Le cœur du simulateur hors interface : réception des commandes, propagation point → zone, affichage des synthèses
toolsnet9.0226Émission et vérification de licences, contre une paire RSA éphémère

Décomptes obtenus en comptant les attributs [Fact], [Theory] et [SkippableFact] : un [Theory] paramétré produit plusieurs cas à l'exécution, si bien que le nombre de tests rapporté par dotnet test est supérieur.

Exécution ​

powershell
dotnet test                                                         # tous les projets, en Debug
dotnet test dotnet/tests/backend/backend.tests.csproj -c Release    # comme l'intégration continue

L'intégration continue répartit ces projets sur deux systèmes : backend, tools et simulator sur Ubuntu, client et manager sur Windows. Les trois premiers ne dépendent d'aucune interface graphique, et doivent le rester.

Mécanismes non évidents ​

Debug et Release ne voient pas le même backend ​

Plusieurs types du backend sont sous #if DEBUG — DemoSeedController, DemoDataSeeder, des actions de MapsController et d'AppConfigsController. Un test qui parcourt l'assembly par réflexion, comme ResourceChangeCoverageTests, voit donc un jeu de types différent selon la configuration : il peut passer en local et échouer sur l'intégration continue, qui compile en Release.

L'assemblage de tests backend déclare son environnement avant le premier test ​

TestEnvironment pose ASPNETCORE_ENVIRONMENT=Testing depuis un [ModuleInitializer].

RaisonDétail
Pourquoi une variable d'environnementLe point d'entrée résout ses chemins de données avant que le constructeur d'hôte n'existe : UseEnvironment arriverait trop tard
Pourquoi un initialiseur de moduleIl s'exécute au chargement de l'assemblage, avant le premier test
Ce que cela éviteSans lui, un test qui téléverse un fichier ou démarre l'hôte écrirait dans les dossiers du service installé — journaux et téléversements compris

Un secret factice est versionné, et lui seul ​

backend/appsettings.Crypto.json est le seul fichier appsettings.Crypto.* versionné du dépôt, explicitement dé-ignoré par .gitignore. Le démarrage du backend refuse un secret absent : sans ce fichier, WebApplicationFactory<Program> ne pourrait pas construire l'hôte. Il est copié en Always pour primer sur l'artefact transitif hérité du projet backend, et la constante FireSupervisorApiFactory.SuperAdminPassword doit rester alignée sur sa valeur.

Deux bases de test, deux usages ​

FournisseurUsageLimite
EF Core InMemoryMajorité des tests de service et de dépôtNe connaît ni ExecuteDelete, ni les contraintes relationnelles ; GetDbConnection() y lève, d'où les gardes IsRelational() du code de production
SQLiteTests exigeant un fournisseur relationnel—

TestDatabaseFixture crée une base InMemory par identifiant unique et l'expose via la collection xUnit DatabaseCollection.

Les tests de licence n'embarquent aucune clé de production ​

tools/LicenseSigningHelper.cs génère une paire RSA 2048 éphémère au chargement et l'injecte dans LicenseVerifier.Validate. La chaîne complète — contenu, signature, empreinte, expiration — est ainsi éprouvée sans qu'aucune clé privée n'entre dans le dépôt. Validate_AgainstTheProductionKey_RejectsTestLicenses vérifie de plus qu'une licence signée par cette clé de test est refusée par la clé publique de production. Le projet client, lui, n'émet aucune licence : il n'éprouve que les refus.

Neuf tests se sautent d'eux-mêmes selon l'environnement ​

Xunit.SkippableFact marque un test ignoré plutôt qu'en échec quand son préalable manque.

TestsCondition de saut
backend/Application/Security/CryptoConfigProtectorTests.csSkip.IfNot(OperatingSystem.IsWindows()) — DPAPI n'existe que sous Windows
backend/Integration/PostgresMigrationTests.csAucune chaîne de connexion d'administration fournie
tools/LicenseGeneratorTests.csSkip.IfNot(OperatingSystem.IsWindows()) — l'empreinte passe par WMI

Les tests de SecurityVerifier du projet client ne passent pas par ce mécanisme : ils sortent par un return conditionné à Debugger.IsAttached, et sont donc rapportés comme réussis sans avoir rien éprouvé.

Contraintes actives ​

ContrainteConséquence si elle est ignorée
Rejouer en Release dès qu'un type conditionnel ou un test réflexif est touchéLe test passe en local et fait rougir l'intégration continue
backend, tools et simulator ne dépendent d'aucune interface graphiqueIls ne tourneraient plus sur les agents Ubuntu de l'intégration continue
HardwareInfo passe par WMILes tests qui en dépendent se sautent hors Windows
PostgresMigrationTests exige une chaîne de connexion d'administrationSans elle, la suite est ignorée : une migration cassée passerait inaperçue

Documentation Technique