Övning – Åtgärda ett misslyckat test
Nu kan du köra enhetstester när ändringarna flyttas genom bygg-pipelinen. Du kan också mäta mängden kod som omfattas av dina tester.
Det är alltid en bra idé att köra dina tester lokalt innan du skickar ändringar till pipelinen. Men vad händer när någon glömmer och skickar in en ändring som bryter bygget?
I den här lektionen ska du åtgärda en trasig version som orsakas av ett misslyckat enhetstest. Här gör du följande:
- Hämta startkod från GitHub.
- Lägg till verktyg för kodtäckning i projektet.
- Skicka koden till lagringsplatsen.
- Se hur pipelinen körs automatiskt och enhetstesterna misslyckas.
- Återskapa felet lokalt.
- Analysera och åtgärda felet.
- Push-överför en korrigering och se hur bygget lyckas.
Granska det nya enhetstestet
Teamets senaste funktion omfattar rankningslistan. Vi måste hämta antalet poäng från databasen, så att vi kan skriva ett enhetstest för att verifiera IDocumentDBRepository<T>.GetItemsAsync
metoden.
Så här ser testet ut. Du behöver inte lägga till någon kod än.
[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();
}
Kom ihåg att i ett NUnit-test TestCase
innehåller infogade data att använda för att testa den metoden. NUnit anropar ReturnRequestedCount
enhetstestmetoden så här:
ReturnRequestedCount(0);
ReturnRequestedCount(1);
ReturnRequestedCount(10);
Det här testet använder ExpectedResult
också egenskapen för att förenkla testkoden och göra avsikten tydlig. NUnit jämför automatiskt returvärdet med värdet för den här egenskapen, vilket tar bort behovet av att uttryckligen anropa försäkran.
Vi väljer några värden som representerar vanliga frågor. Vi inkluderar även 0 för att täcka det kantfallet.
Hämta grenen från GitHub
Som du gjorde tidigare hämtar du grenen failed-test
från GitHub och checkar ut (eller växlar till) den grenen.
Öppna den integrerade terminalen i Visual Studio Code.
Kör följande
git fetch
kommandon ochgit checkout
för att ladda ned en gren med namnetfailed-test
från Microsoft-lagringsplatsen och växla till den grenen:git fetch upstream failed-test git checkout -B failed-test upstream/failed-test
Vi namngav grenen
failed-test
i utbildningssyfte. I praktiken namnger du en gren efter dess syfte eller funktion.Kör dessa kommandon för att skapa en manifestfil för lokala verktyg, installera
ReportGenerator
verktyget och lägg till paketet icoverlet.msbuild
testprojektet:dotnet new tool-manifest dotnet tool install dotnet-reportgenerator-globaltool dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
Du behöver det här steget eftersom grenen
failed-test
inte innehåller det arbete som du har lagt till i grenenunit-tests
.Lägg till testprojektfilen och verktygsmanifestfilen i mellanlagringsindexet och genomför ändringarna.
git add Tailspin.SpaceGame.Web.Tests/Tailspin.SpaceGame.Web.Tests.csproj git add .config/dotnet-tools.json git commit -m "Configure code coverage tests"
Kör följande
git push
kommando för att ladda upp grenenfailed-test
till din GitHub-lagringsplats:git push origin failed-test
Se testfelet i pipelinen
Låt oss säga att du hade bråttom och sköt upp ditt arbete utan att köra testerna en sista gång. Som tur är kan pipelinen hjälpa dig att fånga upp problem tidigt när det finns enhetstester. Du kan se det här.
I Azure Pipelines spårar du bygget när det körs via pipelinen.
Expandera körningsenhetens tester – Släpp aktiviteten medan den körs.
Du ser att
ReturnRequestedCount
testmetoden misslyckas.Testet godkänns när indatavärdet är 0, men det misslyckas när indatavärdet är 1 eller 10.
Bygget publiceras endast till pipelinen när den tidigare uppgiften lyckas. Här publicerades inte bygget eftersom enhetstesterna misslyckades. Detta hindrar andra från att oavsiktligt få en trasig version.
I praktiken spårar du inte alltid bygget manuellt när det körs. Här följer några sätt att upptäcka felet:
Ett e-postmeddelande från Azure DevOps
Du kan konfigurera Azure DevOps så att du får ett e-postmeddelande när bygget är klart. Ämnesraden börjar med "[Build failed]" när bygget misslyckas.
Azure-testplaner
I Azure DevOps väljer du Testplaner och sedan Körningar. Du ser de senaste testkörningarna, inklusive den som just kördes. Välj det senaste slutförda testet. Du ser att två av de åtta testerna misslyckades.
Instrumentpanelen
I Azure DevOps väljer du Översikt och sedan Instrumentpaneler. Felet visas i widgeten Trend för testresultat . Widgeten Kodtäckning är tom, vilket indikerar att kodtäckningen inte kördes.
Byggmärket
Även om grenen
failed-test
inte innehåller byggmärket i README.md-filen visas det här på GitHub när bygget misslyckas:
Analysera testfelet
När enhetstester misslyckas har du vanligtvis två alternativ, beroende på typen av fel:
- Om testet visar en defekt i koden kan du åtgärda koden och köra testerna igen.
- Om funktionen ändras justerar du testet så att det matchar de nya kraven.
Återskapa felet lokalt
I det här avsnittet återskapar du felet lokalt.
Öppna den integrerade terminalen i Visual Studio Code.
I terminalen kör du det här
dotnet build
kommandot för att skapa programmet:dotnet build --configuration Release
Kör det här
dotnet test
kommandot i terminalen för att köra enhetstesterna:dotnet test --no-build --configuration Release
Du bör se samma fel som du såg i pipelinen. Här är en del av utdata:
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
Hitta orsaken till felet
Du märker att varje misslyckat test ger ett resultat som är inaktiverat med ett. När till exempel 10 förväntas returnerar testet 9.
Ta en titt på källkoden för den metod som testas, LocalDocumentDBRepository<T>.GetItemsAsync
. Du bör se följande:
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);
}
I det här scenariot kan du kontrollera GitHub för att se om filen nyligen har ändrats.
Du misstänker att pageSize - 1
returnerar ett resultat färre och att detta bara ska vara pageSize
. I vårt scenario är det här ett fel som du gjorde när du push-överförde arbete utan testning, men i ett verkligt scenario kan du kontrollera med utvecklaren som ändrade filen på GitHub för att fastställa orsaken till ändringen.
Dricks
Diskussioner och samarbete kan också ske på GitHub. Du kan kommentera en pull-begäran eller öppna ett problem.
Åtgärda felet
I det här avsnittet åtgärdar du felet genom att ändra tillbaka koden till dess ursprungliga tillstånd och köra testerna för att verifiera korrigeringen.
I Visual Studio Code öppnar du Tailspin.SpaceGame.Web/LocalDocumentDBRepository.cs från utforskaren.
GetItemsAsync
Ändra metoden enligt följande: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); }
Den här versionen ändras
pageSize - 1
tillpageSize
.Spara filen.
Skapa programmet i den integrerade terminalen.
dotnet build --configuration Release
Du bör se att bygget lyckas.
I praktiken kan du köra appen och kort prova den. I utbildningssyfte hoppar vi över det för tillfället.
Kör enhetstesterna i terminalen.
dotnet test --no-build --configuration Release
Du ser att testerna godkänns.
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
I den integrerade terminalen lägger du till varje modifierad fil i indexet, checkar in ändringarna och push-överför grenen till GitHub.
git add . git commit -m "Return correct number of items" git push origin failed-test
Dricks
Punkten (
.
) i det härgit add
exemplet är ett jokertecken. Den matchar alla otaglade filer i den aktuella katalogen och alla underkataloger.Innan du använder det här jokertecknet är det en bra idé att köra
git status
innan du checkar in för att säkerställa att du mellanlagra de filer som du tänker mellanlagra.Gå tillbaka till Azure Pipelines. Se hur ändringen flyttas genom pipelinen. Testerna godkänns och den övergripande versionen lyckas.
Om du vill verifiera testresultaten kan du välja flikarna Test och Kodtäckning när bygget är klart.
Du kan också kolla in instrumentpanelen för att visa den uppdaterade resultattrenden.
Toppen! Du har fixat bygget. Nu får du lära dig hur du rensar din Azure DevOps-miljö.