Exercice : Corriger un test ayant échoué
À ce stade, vous disposez d’un moyen d’exécuter des tests unitaires quand les modifications progressent dans le pipeline de build. Vous avez également un moyen de mesurer la quantité de code couverte par vos tests.
Il est toujours judicieux d’exécuter vos tests localement avant d’envoyer les modifications au pipeline. Mais que se passe-t-il quand quelqu’un oublie et envoie une modification qui endommage la build ?
Dans cette unité, vous corrigerez un build défectueux causé par un test unitaire défaillant. Vous pourrez ainsi :
- Obtenir le code de démarrage auprès de GitHub.
- Ajouter des outils de couverture du code à votre projet.
- Pousser (push) le code vers le dépôt.
- Regarder le pipeline s’exécuter automatiquement et les tests unitaires échouer.
- Reproduire l’échec localement.
- Analyser et corriger l’échec.
- Pousser (push) un correctif et regarder la build réussir.
Passer en revue le nouveau test unitaire
La dernière caractéristique de l'équipe concerne le leaderboard. Nous devons obtenir le nombre de scores de la base de données, afin d'écrire un test unitaire pour vérifier la méthode IDocumentDBRepository<T>.GetItemsAsync
.
Voici à quoi ressemble le test. Vous n’avez pas besoin d’ajouter de code pour l’instant.
[TestCase(0, ExpectedResult=0)]
[TestCase(1, ExpectedResult=1)]
[TestCase(10, ExpectedResult=10)]
public int ReturnRequestedCount(int count)
{
const int PAGE = 0; // take the first page of results
// Fetch the scores.
Task<IEnumerable<Score>> scoresTask = _scoreRepository.GetItemsAsync(
score => true, // return all scores
score => 1, // we don't care about the order
PAGE,
count // fetch this number of results
);
IEnumerable<Score> scores = scoresTask.Result;
// Verify that we received the specified number of items.
return scores.Count();
}
Rappelez-vous que, dans un test NUnit, TestCase
fournit des données inline à utiliser pour tester cette méthode. NUnit appelle la méthode de test unitaire ReturnRequestedCount
comme suit :
ReturnRequestedCount(0);
ReturnRequestedCount(1);
ReturnRequestedCount(10);
Ce test utilise également la propriété ExpectedResult
pour simplifier le code de test et clarifier sa finalité. NUnit compare automatiquement la valeur de retour à la valeur de cette propriété ; ainsi, il n’est pas nécessaire d’appeler l’assertion explicitement.
Nous allons choisir quelques valeurs qui représentent des requêtes typiques. Nous allons également inclure 0 pour couvrir ce cas limite.
Récupérer (fetch) la branche à partir de GitHub
Comme dans le cas précédent, récupérez la branche failed-test
sur GitHub et extrayez-la (ou basculez vers elle).
Dans Visual Studio Code, ouvrez le terminal intégré.
Exécutez les commandes
git fetch
etgit checkout
suivantes pour télécharger une branche nomméefailed-test
à partir du dépôt Microsoft, puis basculez sur cette branche :git fetch upstream failed-test git checkout -B failed-test upstream/failed-test
Pour cette formation, nous allons appeler la branche
failed-test
. En pratique, vous nommerez une branche d'après son objectif ou sa caractéristique.Exécutez les commandes suivantes pour créer un fichier manifeste d’outils locaux, installez l’outil
ReportGenerator
, puis ajoutez le packagecoverlet.msbuild
à votre projet de tests :dotnet new tool-manifest dotnet tool install dotnet-reportgenerator-globaltool dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
Vous avez besoin de cette étape, car la branche
failed-test
ne contient pas le travail que vous avez ajouté à la brancheunit-tests
.Ajoutez votre fichier de projet de tests et votre fichier manifeste d’outils à l’index de préproduction et commitez vos modifications.
git add Tailspin.SpaceGame.Web.Tests/Tailspin.SpaceGame.Web.Tests.csproj git add .config/dotnet-tools.json git commit -m "Configure code coverage tests"
Exécutez la commande
git push
suivante pour charger la branchefailed-test
sur votre dépôt GitHub :git push origin failed-test
Voir l’échec du test dans le pipeline
Supposons que vous étiez pressé et que vous avez envoyé votre travail sans exécuter les tests une dernière fois. Heureusement, le pipeline peut vous aider à identifier les problèmes tôt quand il y a des tests unitaires. Vous pouvez voir cela ici.
Dans Azure Pipelines, suivez la build au fil du pipeline.
Développez la tâche Run unit tests - Release quand elle s’exécute.
Vous pouvez constater que la méthode de test
ReturnRequestedCount
échoue.Le test réussit quand la valeur d’entrée est 0, mais échoue quand elle est 1 ou 10.
La build n’est publiée dans le pipeline que si la tâche précédente réussit. Ici, la build n’a pas été publiée, car les tests unitaires ont échoué. Ainsi, il est impossible que d’autres personnes obtiennent accidentellement une build endommagée.
Dans la pratique, vous ne suivez pas toujours manuellement la build à mesure qu’elle s’exécute. Voici quelques façons de découvrir l’échec :
Une notification par e-mail provenant d’Azure DevOps
Vous pouvez configurer Azure DevOps pour vous envoyer une notification par e-mail quand la build est terminée. La ligne Objet commence par « [Échec de la build] » quand la build échoue.
Azure Test Plans
Dans Azure DevOps, sélectionnez Plans de test, puis sélectionnez Exécutions. Les séries de tests récentes apparaissent, y compris celle que vous venez d’exécuter. Sélectionnez le dernier test terminé. Vous pouvez constater que deux des huit tests ont échoué.
Le tableau de bord
Dans Azure DevOps, sélectionnez Vue d’ensemble, puis Tableaux de bord. L’échec apparaît dans le widget Tendance des résultats des tests. Le widget Code Coverage est vide, indiquant que la couverture du code n’a pas été exécutée.
Le badge de build
Bien que la branche
failed-test
ne comporte pas le badge de build dans README.md, voici ce que vous voyez sur GitHub en cas d’échec de la build :
Analyser l’échec du test
Quand des tests unitaires échouent, vous avez normalement deux options, selon la nature de l’échec :
- Si le test révèle un défaut dans le code, corrigez le code et relancez les tests.
- Si la fonctionnalité change, ajustez le test afin qu’il tienne compte des nouvelles exigences.
Reproduire l’échec localement
Dans cette section, vous allez reproduire la défaillance localement.
Dans Visual Studio Code, ouvrez le terminal intégré.
Dans le terminal, exécutez cette commande
dotnet build
pour générer l’application :dotnet build --configuration Release
Dans le terminal, exécutez cette commande
dotnet test
pour exécuter les tests unitaires :dotnet test --no-build --configuration Release
Vous devriez voir les mêmes erreurs que dans le pipeline. Voici une partie de la sortie :
Starting test execution, please wait... A total of 1 test files matched the specified pattern. Failed ReturnRequestedCount(1) [33 ms] Error Message: Expected: 1 But was: 0 Stack Trace: at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context) at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0() at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action) Failed ReturnRequestedCount(10) [1 ms] Error Message: Expected: 10 But was: 9 Stack Trace: at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context) at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0() at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action) Failed! - Failed: 2, Passed: 6, Skipped: 0, Total: 8, Duration: 98 ms
Rechercher la cause de l’erreur
Vous remarquez que chaque test échoué produit un résultat qui est décalé d'une unité. Par exemple, quand le résultat attendu est 10, le test retourne 9.
Examinez le code source de la méthode testée, LocalDocumentDBRepository<T>.GetItemsAsync
. Vous devriez voir ce qui suit :
public Task<IEnumerable<T>> GetItemsAsync(
Func<T, bool> queryPredicate,
Func<T, int> orderDescendingPredicate,
int page = 1, int pageSize = 10
)
{
var result = _items
.Where(queryPredicate) // filter
.OrderByDescending(orderDescendingPredicate) // sort
.Skip(page * pageSize) // find page
.Take(pageSize - 1); // take items
return Task<IEnumerable<T>>.FromResult(result);
}
Dans ce scénario, vous pouvez vérifier GitHub pour voir si le fichier a été récemment modifié.
Vous soupçonnez que pageSize - 1
renvoie un résultat minoré et qu'il ne devrait s'agir que de pageSize
. Dans notre scénario, il s'agit d'une erreur que vous avez effectuée lorsque vous avez envoyé (push) un travail sans test. Toutefois, dans un scénario réel, vous pouvez vérifier avec le développeur qui a modifié le fichier sur GitHub pour déterminer la raison de la modification.
Conseil
La discussion et la collaboration peuvent également se produire sur GitHub. Vous pouvez commenter une demande de tirage (pull request) ou ouvrir un problème.
Corriger l’erreur
Dans cette section, vous corrigerez l'erreur en remettant le code dans son état d'origine et en exécutant les tests pour vérifier la correction.
Dans Visual Studio Code, ouvrez Tailspin.SpaceGame.Web/LocalDocumentDBRepository.cs depuis l’Explorateur de fichiers.
Modifiez la section
GetItemsAsync
, comme indiqué ici :public Task<IEnumerable<T>> GetItemsAsync( Func<T, bool> queryPredicate, Func<T, int> orderDescendingPredicate, int page = 1, int pageSize = 10 ) { var result = _items .Where(queryPredicate) // filter .OrderByDescending(orderDescendingPredicate) // sort .Skip(page * pageSize) // find page .Take(pageSize); // take items return Task<IEnumerable<T>>.FromResult(result); }
Cette version remplace
pageSize - 1
parpageSize
.Enregistrez le fichier .
Dans le terminal intégré, générez l’application.
dotnet build --configuration Release
Vous devriez voir que le build réussit.
Dans la pratique, vous pourriez exécuter l’application et l’essayer brièvement. À des fins d’apprentissage, nous allons omettre cette étape pour l’instant.
Dans le terminal, exécutez les tests unitaires.
dotnet test --no-build --configuration Release
Vous voyez que les tests réussissent.
Starting test execution, please wait... A total of 1 test files matched the specified pattern. Passed! - Failed: 0, Passed: 8, Skipped: 0, Total: 8, Duration: 69 ms
Dans le terminal intégré, ajoutez chaque fichier modifié à l’index, commitez les modifications, puis poussez la branche vers GitHub.
git add . git commit -m "Return correct number of items" git push origin failed-test
Conseil
Dans cet exemple
git add
, le point (.
) est un caractère générique. Il correspond à tous les fichiers non mis en attente qui se trouvent dans le répertoire actif et dans tous les sous-répertoires.Avant d'utiliser ce caractère générique, il est recommandé d'exécuter
git status
avant de valider pour s'assurer que vous mettez en lots les fichiers concernés.Retournez à Azure Pipelines. Observez la progression de la modification dans le pipeline. Les tests réussissent, de même que la build globale.
Si vous le souhaitez, pour vérifier les résultats des tests, vous pouvez sélectionner les onglets Tests et Couverture du code quand la build est terminée.
Vous pouvez également consulter le tableau de bord pour voir la tendance des résultats mise à jour.
Très bien ! Vous avez corrigé le build. Vous apprendrez ensuite à nettoyer votre environnement Azure DevOps.