Share via


Dag i livet för en devops-utvecklare: Skriv ny kod för en användarberättelse

Azure DevOps Services | Azure DevOps Server 2022 – Azure DevOps Server 2019

Visual Studio 2019 | Visual Studio 2022

Den här självstudien beskriver hur du och ditt team kan få största möjliga nytta av de senaste versionerna av Team Foundation Version Control (TFVC) och Visual Studio för att skapa din app. Självstudien innehåller exempel på hur du kan använda Visual Studio och TFVC för att checka ut och uppdatera kod, pausa arbetet när du avbryts, begära en kodgranskning, checka in dina ändringar och utföra andra uppgifter.

När ett team använder Visual Studio och TFVC för att hantera sin kod konfigurerar de sina server- och klientdatorer, skapar en kvarvarande information, planerar en iteration och slutför annan planering som krävs för att börja utveckla appen.

Utvecklare granskar sina kvarvarande uppgifter för att välja uppgifter att arbeta med. De skriver enhetstester för den kod som de planerar att utveckla. Vanligtvis kör de testerna flera gånger på en timme, skriver gradvis mer detaljerade tester och skriver sedan koden som gör att de godkänns. Utvecklare diskuterar ofta sina kodgränssnitt med kollegor som använder den metod de skriver.

Visual Studio My Work - och Code Review-verktygen hjälper utvecklare att hantera sitt arbete och samarbeta med kollegor.

Kommentar

Visual Studio My Work - och Code Review-funktioner är tillgängliga med följande utgåvor:

  • Visual Studio 2022: Visual Studio Community, Visual Studio Professional och Visual Studio Enterprise
  • Visual Studio 2019: Visual Studio Professional och Visual Studio Enterprise

Granska arbetsobjekt och förbered för att börja arbeta

Teamet har kommit överens om att du under den aktuella sprinten ska arbeta med Utvärdera fakturastatus, ett objekt med högsta prioritet i produktinformationen. Du bestämmer dig för att börja med Implementera matematiska funktioner, en underordnad uppgift för det högsta prioritetsobjektet för kvarvarande uppgifter.

På sidan Mitt arbete i Visual Studio Team Explorer drar du den här uppgiften från listan Tillgängliga arbetsobjekt till listan Pågående arbete.

Så här granskar du kvarvarande uppgifter och förbereder uppgifter för att påbörja arbetet

Skärmbild av sidan Mitt arbete.

  1. Om du inte redan är ansluten till det projekt som du vill arbeta i i Team Explorer ansluter du till projektet.

  2. På sidan Start väljer du Mitt arbete.

  3. På sidan Mitt arbete drar du aktiviteten från listan Tillgängliga arbetsobjekt till avsnittet Pågår arbete .

    Du kan också välja uppgiften i listan Tillgängliga arbetsobjekt och sedan välja Start.

Utkast till inkrementell arbetsplan

Du utvecklar kod i en serie små steg. Varje steg tar vanligtvis inte längre än en timme och kan ta så lite som 10 minuter. I varje steg skriver du ett nytt enhetstest och ändrar koden du utvecklar så att den klarar det nya testet, utöver de tester som du redan har skrivit. Ibland skriver du det nya testet innan du ändrar koden, och ibland ändrar du koden innan du skriver testet. Ibland omstrukturerar du. Du kan alltså bara förbättra koden utan att lägga till nya tester. Du ändrar aldrig ett test som godkänns, såvida du inte bestämmer dig för att det inte korrekt motsvarar ett krav.

I slutet av varje litet steg kör du alla enhetstester som är relevanta för det här området i koden. Du anser inte att steget är klart förrän varje test har slutförts.

Du checkar inte in koden till Azure DevOps Server förrän du har slutfört hela aktiviteten.

Du kan skriva ned en grov plan för den här sekvensen med små steg. Du vet att den exakta informationen och ordningen för de senare förmodligen kommer att ändras när du arbetar. Här är den första listan med steg för den här uppgiften:

  1. Skapa testmetoden stub, det vill s.v.s. bara metodens signatur.
  2. Uppfylla ett specifikt typiskt fall.
  3. Testa ett brett intervall. Kontrollera att koden svarar korrekt på ett stort antal värden.
  4. Undantag vid negativ. Hantera felaktiga parametrar på ett korrekt sätt.
  5. Kodtäckning. Kontrollera att minst 80 % av koden används i enhetstesterna.

Vissa utvecklare skriver den här typen av plan i kommentarer i sin testkod. Andra memorerar bara sin plan. Det kan vara användbart att skriva en lista med steg i fältet Beskrivning i arbetsobjektet Aktivitet. Om du tillfälligt måste byta till en mer brådskande uppgift vet du var du hittar listan när du kan återgå till den.

Skapa det första enhetstestet

Börja med att skapa ett enhetstest. Börja med enhetstestet eftersom du vill skriva ett exempel på kod som använder din nya klass.

Det här är det första enhetstestet för klassbiblioteket som du testar, så du skapar ett nytt enhetstestprojekt.

  1. Välj Fil>nytt projekt.
  2. I dialogrutan Skapa ett nytt projekt väljer du pilen bredvid Alla språk och väljer C#, väljer pilen bredvid Alla projekttyper och väljer Test och sedan MSTest Test Project.
  3. Välj Nästa, och välj Skapa.

Skärmbild av enhetstest som valts i dialogrutan Skapa ett nytt projekt.

Ersätt innehållet i UnitTest1.cs med följande kod i kodredigeraren. I det här skedet vill du bara illustrera hur en av dina nya metoder kommer att anropas:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Fabrikam.Math.UnitTest
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        // Demonstrates how to call the method.
        public void SignatureTest()
        {
            // Create an instance:
            var math = new Fabrikam.Math.LocalMath();

            // Get a value to calculate:
            double input = 0.0;

            // Call the method:
            double actualResult = math.SquareRoot(input);

            // Use the result:
            Assert.AreEqual(0.0, actualResult);
        }
    }
}

Du skriver exemplet i en testmetod eftersom du vill att exemplet ska fungera när du skriver koden.

Skapa ett enhetstestprojekt och metoder

Vanligtvis skapar du ett nytt testprojekt för varje projekt som testas. Om det redan finns ett testprojekt kan du bara lägga till nya testmetoder och klasser.

I den här självstudien används Visual Studio Unit Test Framework, men du kan också använda ramverk från andra leverantörer. Test Explorer fungerar lika bra med andra ramverk, förutsatt att du installerar rätt adapter.

  1. Skapa ett testprojekt med hjälp av föregående steg. Du kan välja språk som C#, F# och Visual Basic.

  2. Lägg till dina tester i testklassen som tillhandahålls. Varje enhetstest är en metod.

    • Varje enhetstest måste föregås av TestMethod attributet och enhetstestmetoden ska inte ha några parametrar. Du kan använda valfritt namn som du vill för en enhetstestmetod:

      [TestMethod]
      public void SignatureTest()
      {...}
      
      <TestMethod()>
      Public Sub SignatureTest()
      ...
      End Sub
      
    • Varje testmetod bör anropa en metod för Assert klassen för att ange om den har godkänts eller misslyckats. Vanligtvis kontrollerar du att de förväntade och faktiska resultaten av en åtgärd är lika med:

      Assert.AreEqual(expectedResult, actualResult);
      
      Assert.AreEqual(expectedResult, actualResult)
      
    • Dina testmetoder kan anropa andra vanliga metoder som inte har attributet TestMethod .

    • Du kan organisera dina tester i mer än en klass. Varje klass måste prefixas av TestClass attributet.

      [TestClass]
      public class UnitTest1
      { ... }
      
      <TestClass()>
      Public Class UnitTest1
      ...
      End Class
      

Information om hur du skriver enhetstester i C++finns i Skriva enhetstester för C/C++ med Microsoft Unit Testing Framework för C++.

Skapa en stub för den nya koden

Skapa sedan ett klassbiblioteksprojekt för din nya kod. Det finns nu ett projekt för koden under utveckling och ett projekt för enhetstesterna. Lägg till en projektreferens från testprojektet i koden under utveckling.

Skärmbild av Solution Explorer med test- och klassprojekt.

I det nya projektet lägger du till den nya klassen och en minimal version av metoden som åtminstone tillåter att testet skapas. Det snabbaste sättet att göra det är att generera en klass- och metodstub från anropet i testet.

public double SquareRoot(double p)
{
    throw new NotImplementedException();
}

Generera klasser och metoder från tester

Skapa först projektet där du vill lägga till den nya klassen, såvida den inte redan finns.

Generera en klass

  1. Placera markören på ett exempel på den klass som du vill generera, LocalMathtill exempel , och välj Snabbåtgärder och Refaktoriseringar.
  2. På snabbmenyn väljer du Generera ny typ.
  3. I dialogrutan Generera typ anger du Projekt till klassbiblioteksprojektet. I det här exemplet är det Fabrikam.Math.

Så här genererar du en metod

  1. Placera markören på ett anrop till metoden, SquareRoottill exempel , och välj Snabbåtgärder och Refaktoriseringar.
  2. På snabbmenyn väljer du Generera -metoden "SquareRoot".

Kör det första testet

Skapa och kör testet. Testresultatet visar en röd misslyckad indikator och testet visas under listan över misslyckade tester.

Skärmbild av Test Explorer som visar ett misslyckat test.

Gör en enkel ändring i koden:

public double SquareRoot(double p)
{
    return 0.0;
}

Kör testet igen och det godkänns.

Skärmbild av Enhetstestutforskaren med ett godkänt test.

Så här kör du enhetstester

Så här kör du enhetstester:

  • Välj Testa>kör alla tester
  • Om TestUtforskaren är öppen väljer du Kör eller Kör alla tester i vyn.

Skärmbild av testutforskaren med knappen Kör alla.

Om ett test visas under Misslyckade tester öppnar du testet, till exempel genom att dubbelklicka på namnet. Den punkt där testet misslyckades visas i kodredigeraren.

  • Om du vill se en fullständig lista över tester väljer du Visa alla.

  • Om du vill se information om ett testresultat väljer du testet i TestUtforskaren.

  • Om du vill navigera till koden för ett test dubbelklickar du på testet i TestUtforskaren eller väljer Öppna test på snabbmenyn.

  • Om du vill felsöka ett test öppnar du snabbmenyn för ett eller flera tester och väljer sedan Felsök.

  • Om du vill köra tester i bakgrunden när du skapar lösningen väljer du pilen bredvid ikonen Inställningar och väljer sedan Kör tester efter build. Tester som tidigare misslyckades körs först.

Komma överens om gränssnittet

Du kan samarbeta med kollegor som ska använda din komponent genom att dela skärmen. En kollega kan kommentera att många funktioner skulle klara föregående test. Förklara att det här testet bara var för att se till att funktionens namn och parametrar är korrekta, och nu kan du skriva ett test som samlar in huvudkravet för den här funktionen.

Du samarbetar med kollegor för att skriva följande test:

[TestMethod]
public void QuickNonZero()
{
    // Create an instance to test:
    LocalMath math = new LocalMath();

    // Create a test input and expected value:
    var expectedResult = 4.0;
    var inputValue = expectedResult * expectedResult;

    // Run the method:
    var actualResult = math.SquareRoot(inputValue);

    // Validate the result:
    var allowableError = expectedResult/1e6;
    Assert.AreEqual(expectedResult, actualResult, allowableError,
        "{0} is not within {1} of {2}", actualResult, allowableError, expectedResult);
}

Dricks

För den här funktionen använder du test först utveckling, där du först skriver enhetstestet för en funktion och sedan skriver kod som uppfyller testet. I andra fall är den här metoden inte realistisk, så du skriver testerna när du har skrivit koden. Men det är mycket viktigt att skriva enhetstester, antingen före eller efter koden, eftersom de håller koden stabil.

Röd, grön, refaktor...

Följ en cykel där du upprepade gånger skriver ett test och bekräftar att det misslyckas, skriver kod för att göra testet godkänd och sedan överväger refaktorisering, som förbättrar koden utan att ändra testerna.

Röd

Kör alla tester, inklusive det nya testet som du skapade. När du har skrivit ett test kör du det alltid för att se till att det misslyckas innan du skriver koden som gör att den godkänns. Om du till exempel glömmer att placera försäkran i vissa tester som du skriver, kan du känna dig säker på att testresultatet korrekt anger att ett krav har uppfyllts när du gör det.

En annan användbar metod är att ange Kör tester efter build. Det här alternativet kör testerna i bakgrunden varje gång du skapar lösningen, så att du får en kontinuerlig rapport om teststatusen för koden. Du kanske är orolig för att den här metoden kan göra Visual Studio långsamt att svara, men det händer sällan.

Skärmbild av Test Explorer med ett misslyckat test.

Grönt

Skriver ditt första försök till koden för den metod som du utvecklar:

public class LocalMath
{
    public double SquareRoot(double x)
    {
        double estimate = x;
        double previousEstimate = -x;
        while (System.Math.Abs(estimate - previousEstimate) > estimate / 1000)
        {
            previousEstimate = estimate;
            estimate = (estimate * estimate - x) / (2 * estimate);
        }
        return estimate;
    }

Kör testerna igen och alla tester godkänns.

Skärmbild av Enhetstestutforskaren med två godkända tester.

Refaktorisering

Nu när koden utför sin huvudfunktion tittar du på koden för att hitta sätt att få den att fungera bättre eller för att göra det enklare att ändra i framtiden. Du kan minska antalet beräkningar som utförs i loopen:

public class LocalMath
{
    public double SquareRoot(double x)
    {
        double estimate = x;
        double previousEstimate = -x;
        while (System.Math.Abs(estimate - previousEstimate) > estimate / 1000)
        {
            previousEstimate = estimate; 
            estimate = (estimate + x / estimate) / 2;
            //was: estimate = (estimate * estimate - x) / (2 * estimate);
        }
        return estimate;
    }

Kontrollera att testerna fortfarande godkänns.

Tips

  • Varje ändring du gör när du utvecklar koden bör antingen vara en refaktorisering eller ett tillägg:

    • Refaktorisering innebär att du inte ändrar testerna eftersom du inte lägger till nya funktioner.
    • Tillägg innebär att lägga till tester och göra de kodändringar som krävs för att klara både befintliga och nya tester.
  • Om du uppdaterar befintlig kod till krav som har ändrats tar du även bort gamla tester som inte längre representerar de aktuella kraven.

  • Undvik att ändra tester som redan har godkänts. Lägg i stället till nya tester. Skriv endast tester som representerar ett verkligt krav.

  • Kör testerna efter varje ändring.

... och upprepa

Fortsätt din serie med tilläggs- och refaktoriseringssteg med hjälp av din lista över små steg som en grov guide. Du utför inte alltid ett refaktoriseringssteg efter varje tillägg, och ibland utför du mer än ett refaktoriseringssteg i följd. Men du kör alltid enhetstesterna efter varje ändring av koden.

Ibland lägger du till ett test som inte kräver någon ändring av koden, men som ökar ditt förtroende för att koden fungerar korrekt. Du vill till exempel se till att funktionen fungerar över ett stort antal indata. Du skriver fler tester, till exempel den här:

[TestMethod]
public void SqRtValueRange()
{
    LocalMath math = new LocalMath();
    for (double expectedResult = 1e-8;
        expectedResult < 1e+8;
        expectedResult = expectedResult * 3.2)
    {
        VerifyOneRootValue(math, expectedResult);
    }
}
private void VerifyOneRootValue(LocalMath math, double expectedResult)
{
    double input = expectedResult * expectedResult;
    double actualResult = math.SquareRoot(input);
    Assert.AreEqual(expectedResult, actualResult, expectedResult / 1e6);
}

Det här testet klarar första gången det körs.

Skärmbild av Test Explorer med tre godkända tester.

Bara för att se till att det här resultatet inte är ett misstag kan du tillfälligt introducera ett litet fel i testet för att göra det fel. När du har sett felet kan du åtgärda det igen.

Dricks

Gör alltid ett test misslyckas innan du klarar det.

Undantag

Gå nu vidare till att skriva tester för exceptionella indata:

[TestMethod]
public void RootTestNegativeInput()
{
    LocalMath math = new LocalMath();
    try
    {
        math.SquareRoot(-10.0);
    }
    catch (ArgumentOutOfRangeException)
    {
        return;
    }
    catch
    {
        Assert.Fail("Wrong exception on negative input");
        return;
    }
    Assert.Fail("No exception on negative input");
}

Det här testet placerar koden i en loop. Du måste använda knappen Avbryt i Testutforskaren. Detta avslutar koden inom 10 sekunder.

Du vill se till att en oändlig loop inte kan ske på byggservern. Även om servern ålägger en timeout på en fullständig körning är det en mycket lång tidsgräns och skulle orsaka betydande fördröjningar. Därför kan du lägga till en explicit timeout i det här testet:

[TestMethod, Timeout(1000)]
public void RootTestNegativeInput()
{...

Den explicita tidsgränsen gör att testet misslyckas.

Uppdatera koden för att hantera det här exceptionella fallet:

public double SquareRoot(double x)
{
    if (x <= 0.0) 
    {
        throw new ArgumentOutOfRangeException();
    }

Regression

Det nya testet godkänns, men det finns en regression. Ett test som användes för att klara misslyckas nu:

Skärmbild av enhetstestet misslyckades som tidigare skickades.

Hitta och åtgärda misstaget:

public double SquareRoot(double x)
{
    if (x < 0.0)  // not <=
    {
        throw new ArgumentOutOfRangeException();
    }

När det har åtgärdats godkänns alla tester:

Skärmbild av Enhetstestutforskaren med fyra godkända tester.

Dricks

Kontrollera att varje test godkänns efter varje ändring som du gör i koden.

Kodtäckning

Med jämna mellanrum under arbetet och slutligen, innan du checkar in koden, får du en kodtäckningsrapport. Detta visar hur mycket av koden som har utövats av dina tester.

Ditt team strävar efter täckning på minst 80 %. De lättar på det här kravet på genererad kod, eftersom det kan vara svårt att uppnå en hög täckning för den här typen av kod.

Bra täckning är inte en garanti för att komponentens fullständiga funktioner har testats, och det garanterar inte att koden fungerar för alla indatavärden. Det finns dock en ganska nära korrelation mellan täckningen av kodrader och täckningen av beteendeutrymmet för en komponent. Därför stärker bra täckning teamets förtroende för att de testar det mesta av det beteende som de borde.

Om du vill hämta en kodtäckningsrapport går du till Visual Studio Test-menyn och väljer Analysera kodtäckning för alla tester. Alla tester körs igen.

Skärmbild av resultatet av kodtäckningen och knappen Visa färg.

När du expanderar summan i rapporten visas att koden du utvecklar har fullständig täckning. Detta är mycket tillfredsställande, eftersom den viktiga poängen är för koden som testas. De oupptäckta avsnitten finns faktiskt i själva testerna.

Genom att växla knappen Visa kodtäckningsfärgning kan du se vilka delar av testkoden som inte har tränats. Kod som inte användes i testerna är markerad i orange. De här avsnitten är dock oviktiga för täckning eftersom de finns i testkoden och endast används om ett fel identifieras.

Om du vill kontrollera att ett visst test når specifika grenar av koden kan du ange Visa kodtäckningsfärgning och sedan köra det enskilda testet med hjälp av kommandot Kör på snabbmenyn.

När är du klar?

Du fortsätter att uppdatera koden i små steg tills du är nöjd med följande:

  • Alla tillgängliga enhetstester godkänns.

    I ett projekt med en mycket stor uppsättning enhetstester kan det vara opraktiskt för en utvecklare att vänta på att alla ska köras. I stället kör projektet en gated check-in-tjänst, där alla automatiserade tester körs för varje incheckad hyllor innan den slås samman i källträdet. Incheckningen avvisas om körningen misslyckas. Detta gör att utvecklare kan köra en minimal uppsättning enhetstester på sina egna datorer och sedan fortsätta med annat arbete, utan att riskera att bryta bygget. Mer information finns i Använda en gated check-in-byggprocess för att verifiera ändringar.

  • Kodtäckningen uppfyller teamets standard. 75 % är ett typiskt projektkrav.

  • Enhetstesterna simulerar alla aspekter av det beteende som krävs, inklusive både typiska och exceptionella indata.

  • Koden är lätt att förstå och utöka.

När alla dessa kriterier uppfylls är du redo att kontrollera koden i källkodskontrollen.

Principer för kodutveckling med enhetstester

Tillämpa följande principer när du utvecklar kod:

  • Utveckla enhetstester tillsammans med koden och kör dem ofta under utvecklingen. Enhetstesterna representerar specifikationen för din komponent.
  • Ändra inte enhetstester, såvida inte kraven har ändrats eller om testerna var felaktiga. Lägg till nya tester gradvis när du utökar funktionen för koden.
  • Sikta på att minst 75 % av koden ska omfattas av testerna. Titta på kodtäckningsresultatet med intervall och innan du checkar in källkoden.
  • Kontrollera enhetstesterna tillsammans med koden så att de körs av de kontinuerliga eller vanliga serverversionerna.
  • När det är praktiskt skriver du enhetstestet först för varje funktionsdel. Gör detta innan du utvecklar koden som uppfyller den.

Kontrollera ändringarna

Innan du checkar in ändringar kan du återigen dela skärmen med kollegor så att de informellt och interaktivt kan granska med dig vad du har skapat. Testerna fortsätter att vara i fokus för din diskussion med kollegor som främst är intresserade av vad koden gör, inte hur den fungerar. Dessa kollegor bör vara överens om att det du har skrivit uppfyller deras behov.

Kontrollera alla ändringar du har gjort, inklusive både testerna och koden, och associera dem med de uppgifter som du har slutfört. Incheckningen köar teamets automatiserade teambyggsystem för att verifiera dina ändringar med hjälp av teamets CI Build-byggprocess . Den här byggprocessen hjälper teamet att minimera fel i sin kodbas genom att skapa och testa, i en ren miljö som är separat från deras utvecklingsdatorer, varje ändring teamet gör.

Du meddelas när bygget har slutförts. I fönstret build-resultat ser du att bygget lyckades och att alla tester har godkänts.

Så här checkar du in ändringarna

  1. På sidan Mitt arbete i Team Explorer väljer du Checka in.

    Skärmbild av incheckning från Mitt arbete.

  2. På sidan Väntande ändringar kontrollerar du att:

    • Alla relevanta ändringar visas i Inkluderade ändringar.
    • Alla relevanta arbetsobjekt visas i Relaterade arbetsobjekt.
  3. Ange en kommentar som hjälper ditt team att förstå syftet med dessa ändringar när de tittar på versionskontrollhistoriken för de ändrade filerna och mapparna.

  4. Välj Incheckning.

    Skärmbild av kontrollen av väntande ändringar.

Så här integrerar du koden kontinuerligt

Mer information om hur du definierar en process för kontinuerlig integrering finns i Konfigurera en CI-version. När du har konfigurerat den här byggprocessen kan du välja att få ett meddelande om resultatet av teamversioner.

Skärmbild av sidan Mina byggen med ett lyckat bygge.

Mer information finns i Kör, övervaka och hantera byggen.

Nästa steg