Dette er et utdrag fra Unit Testing Succinctly eBook, av Marc Clifton, gitt vennlig av Syncfusion.
En enhetstest består av to ting:
En klasse som representerer testfestet.
Metoder i klassen som representerer enhetstester.
Visual Studio lager automatisk en stub for et testprosjekt, som er hvor vi skal starte.
Opprette et enhetstestprosjekt i Visual Studio
Enhetstester plasseres vanligvis i et eget prosjekt (som resulterer i en tydelig sammenstilling) fra søknadskoden. I Visual Studio 2008 eller 2012 kan du opprette et enhetstestprosjekt ved å høyreklikke på løsningen og velge Legg til etterfulgt av Nytt prosjekt fra hurtigmenyen:
Legge til et nytt prosjekt
Fra dialogboksen som vises, velg en Test prosjekt:
VS2008 nytt testprosjekt VS2012 nytt testprosjekt
Visual Studio 2008 vil opprette en stubfil, "UnitTest1.cs" (hvis du valgte C # -språket), med en rekke nyttige kommentarer i stubben. Visual Studio 2012 skaper en mye terser stub:
bruker system; bruker Microsoft.VisualStudio.TestTools.UnitTesting; navneområde VS2012UnitTestProject1 [TestClass] offentlig klasse UnitTest1 [TestMethod] offentlig tomrom TestMethod1 ()
For Visual Studio 2008 Brukere
Visual Studio 2008 vil også opprette en TestContext-klasse - dette eksisterer ikke lenger i VS2012, og vi vil ignorere det - bruk forrige stub fra VS2012 i stedet.
Slett også "ManualTest1.mht" -filen, ellers blir du bedt om å velge testresultater og skrive inn testnotater manuelt.
Testutstyr
Legg merke til at klassen er dekorert med attributtet TestClass. Dette definerer test fixturen-en samling av testmetoder.
Testmetoder
Legg merke til at metoden er dekorert med attributtet TestMethod. Dette definerer en metode som testfestet vil løpe.
Assert-klassen
Assert-klassen definerer følgende statiske metoder som kan brukes til å verifisere beregning av metoden:
AreEqual / AreNotEqual
AreSame / AreNotSame
IsTrue / IsFalse
IsNull / IsNotNull
IsInstanceOfType / IsNotInstanceOfType
Mange av disse påstandene er overbelastet, og det anbefales at du gjennomgår den fulle dokumentasjonen som Microsoft gir.
Grunnlag for å gjøre en påstand
Vær oppmerksom på at følgende eksempler bruker VS2008.
Påstandene er ryggraden i hver test. Det er en rekke påstander som man kan gjøre angående resultatene av en test. Til å begynne med skriver vi en enkel påstand som sier "en er lik en," med andre ord en truisme:
De har formen av å sammenligne den forventede (den første parameteren) med den faktiske (den andre parameterverdien). Med hensyn til enkle og doble verdier kan "innenfor en viss nøyaktighet" spesifiseres. Til slutt har alle overbelastninger muligheten til å vise en melding (eventuelt formatert) hvis påstanden mislykkes.
Med hensyn til objektets likestilling, sammenligner denne metoden om forekomstene er identiske:
offentlig klasse AnObject [TestMethod] public void ObjectEqualityTest () AnObject object1 = nytt AnObject (); AnObject object2 = nytt AnObject (); Assert.AreNotEqual (objekt1, objekt2);
Den foregående testen går, da objekt1 og objekt2 ikke er like. Men hvis klassen tilsidesetter Equals-metoden, er likestillingen basert på sammenligningen laget av Equals-metoden som ble implementert i klassen. For eksempel:
offentlig klasse AnObject public int SomeValue get; sett; offentlig overstyring bool Like (objekt obj) return NoenValue == ((AnObject) obj) .SomeValue; [TestMethod] public void ObjectEqualityTest () AnObject object1 = nytt AnObject () SomeValue = 1; AnObject object2 = nytt AnObject () SomeValue = 1; Assert.AreEqual (objekt1, objekt2);
AreSame / AreNotSame
Disse to metodene verifiserer at forekomster er det samme (eller ikke). For eksempel:
[TestMethod] public void SamenessTest () AnObject object1 = nytt AnObject () SomeValue = 1; AnObject object2 = nytt AnObject () SomeValue = 1; Assert.AreNotSame (object1, object2);
Selv om klassen AnObject overstyrer Equals-operatøren, passerer den foregående testen fordi forekomster av de to objektene er ikke det samme.
IsTrue / IsFalse
Disse to metodene tillater deg å teste sannheten til en verdi sammenligning. Fra et lesbarhetsperspektiv benyttes IsTrue og IsFalse-metodene vanligvis for verdi sammenligninger, mens AreEqual og AreSame vanligvis brukes til å sammenligne forekomster (objekter).
For eksempel:
[TestMethod] public void IsTrueTest () AnObject object1 = nytt AnObject () SomeValue = 1; Assert.IsTrue (object1.SomeValue == 1);
Dette bekrefter verdien av en eiendom.
IsNull / IsNotNull
Disse to testene verifiserer om en gjenstand er null eller ikke:
Assert.Inclusive-metoden kan brukes til å angi at enten testen eller funksjonaliteten bak testen ennå ikke er implementert, og derfor er testen utilsiktet.
Hva skjer når en påstand mislykkes?
Når det gjelder test av Visual Studio-enhet, kaster Assert-metoden en AssertFailedException når et påstand mislykkes. Dette unntaket bør aldri håndteres av testkoden.
Andre assertjonsklasser
Det er to andre påstandsklasser:
CollectionAssert
StringAssert
Som navnene antyder, gjelder disse påstandene henholdsvis på samlinger og strenger.
Samling påstander
Disse metodene er implementert i Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert-klassen. Vær oppmerksom på at samlingsparameteren i disse metodene forventer at samlingen skal implementere ICollection (kontrast dette med NUnit, som forventer IEnumerable).
AllItemsAreInstanceOfType
Denne påstanden verifiserer at objekter i en samling er av samme type, som inkluderer avledede typer av den forventede typen, som illustrert her:
offentlig klasse A offentlig klasse B: A [TestClass] offentlig klasse Samlingstester [TestMethod] offentlig tomgang InstancesOfTypeTest () Liste punkter = ny liste () nytt punkt (1, 2), nytt punkt ); Liste
AllItemsAreNotNull
Denne påstanden verifiserer at objekter i samlingen ikke er null.
AllItemsAreUnique
Denne testen sikrer at objekter i en samling er unike. Hvis man sammenligner strukturer:
[TestMethod] public void AreUniqueTest () Liste punkter = ny liste () nytt punkt (1, 2), nytt punkt (1, 2); CollectionAssert.AllItemsAreUnique (poeng);
strukturene er sammenlignet med verdi, ikke for eksempel - den foregående testen feiler. Men selv om klassen tilsidesetter Equals-metoden:
offentlig klasse AnObject public int SomeValue get; sett; offentlig overstyring bool Like (objekt obj) return NoenValue == ((AnObject) obj) .SomeValue;
denne testen passerer:
[TestMethod] public void AreUniqueObjectsTest () Liste elementer = ny liste() new AnObject () SomeValue = 1, ny AnObject () SomeValue = 1; CollectionAssert.AllItemsAreUnique (eks);
AreEqual / AreNotEqual
Disse testene hevder at to samlinger er like. Metodene inkluderer overbelastninger som lar deg gi en komparator metode. Hvis et objekt tilsidesøker Equals-metoden, brukes denne metoden til å bestemme likestilling. For eksempel:
[TestMethod] public void AreEqualTest () Liste itemList1 = ny liste() new AnObject () SomeValue = 1, ny AnObject () SomeValue = 2; Liste itemList2 = ny liste() new AnObject () SomeValue = 1, ny AnObject () SomeValue = 2; CollectionAssert.AreEqual (itemList1, itemList2);
Disse to samlingene er like fordi klassen AnObject overstyrer Equals-metoden (se forrige eksempel).
Merk at for å passere påstanden, må listerne være av samme lengde og anses ikke like om lister er identiske bortsett fra i en annen rekkefølge. Sammenlign dette med AreEquivalent påstanden som er beskrevet nedenfor.
AreEquivalent / AreNotEquivalent
Denne påstanden sammenligner to lister og vurderer lister over like elementer som ekvivalente uansett rekkefølge. Dessverre ser det ut til å være en feil i implementeringen, da denne testen mislykkes:
[TestMethod] public void AreEqualTest () Liste itemList1 = ny liste() new AnObject () SomeValue = 1, ny AnObject () SomeValue = 2; Liste itemList2 = ny liste() new AnObject () SomeValue = 2, ny AnObject () SomeValue = 1; CollectionAssert.AreEquivalent (itemList1, itemList2);
Visual Studio er Equivalent Bug
med feilmeldingen:
CollectionAssert.AreEquivalent mislyktes. Den forventede samlingen inneholder 1 forekomst (er) av. Den faktiske samlingen inneholder 0 forekomst (er).
Mens NUnits implementering av denne påstanden passerer:
NUnits AreEquivalent Works Korrekt
Inneholder / DoesNotContain
Denne påstanden verifiserer at et objekt er inneholdt i en samling:
[TestMethod] public void ContainsTest () Liste itemList = ny liste() new AnObject () SomeValue = 1, ny AnObject () SomeValue = 2; CollectionAssert.Contains (itemList, new AnObject () SomeValue = 1);
bruker Equals-metoden (hvis overstyrt) for å utføre likestiltesten.
IsSubsetOf / IsNotSubsetOf
Denne påstanden verifiserer at den første parameteren (delmengden) er inneholdt i den andre parameterens samling (supersettet).
Vær oppmerksom på at undersettprøven ikke tester for rekkefølge eller sekvens - det tester bare om elementene i delmengelisten er inneholdt i supersettet.
String påstander
Disse metodene implementeres i Microsoft.VisualStudio.TestTools.UnitTesting.StringAssert-klassen:
inneholder
Kamper / DoesNotMatch
Starts / EndsWith
Disse blir diskutert neste.
inneholder
Inneholder metoden hevder at delmengden (merk at dette er den andre parameteren) finnes i strengen (den første parameteren). For eksempel passerer denne testen:
Det er noen ekstra attributter som er nyttige for å kjøre en serie tester, samt individuelle tester som forbedrer gjenbrukbarheten og lesbarheten til enhetstestkoden.
Visual Studio enhet testmotor gir fire ekstra metoden attributter:
ClassInitialize
ClassCleanup
TestInitialize
TestCleanup
Disse egenskapene foregår og følger utførelsen av alle tester i fixturen (klassen), så vel som før og etter hver test i fixturen.
Vær oppmerksom på at metodene som er dekorert med dette attributtet må være statiske.
ClassInitialize
Hvis en metode er dekorert med dette attributtet, kjøres koden i metoden før alle tester i fixturen kjøres. Merk at denne metoden krever en TestContext-parameter.
Denne metoden er nyttig for å tildele ressurser eller instantiere klasser som alle testene i fixturen stole på. En viktig overveielse med ressurser og objekter opprettet under oppstart av innretningen er at disse ressursene og objektene skal betraktes som skrivebeskyttet. Det er ikke tilrådelig for tester å endre tilstanden til ressurser og gjenstander som andre tester er avhengige av. Dette inkluderer tilkoblinger til tjenester som databaser og webtjenester hvis forbindelsen kan bli satt i ugyldig tilstand som følge av en feil i en test, og dermed ugyldiggjør alle de andre testene. Videre er rekkefølgen der tester kjører ikke garantert. Hvis du endrer tilstanden til en ressurs og objekt som er opprettet i oppstartspartiets initialisering, kan det føre til bivirkninger, avhengig av rekkefølgen der tester kjøres.
ClassCleanup
En metode dekorerte med dette attributtet er ansvarlig for deallokering av ressurser, lukkekoblinger, etc., som ble opprettet under klassens initialisering. Denne metoden vil alltid utføres etter å ha kjørt testene i fixturen, uavhengig av suksessen eller feilen i testene selv.
TestInitialize
På samme måte som ClassInitialize-attributtet, vil en metode som er dekorert med dette attributtet, bli utført for hver test før du kjører testen. Et av formålene med dette attributtet er å sikre at ressurser eller objekter som er tildelt av ClassInitialize-koden, initialiseres til en kjent tilstand før de kjører hver test.
TestCleanup
I tillegg til TestInitialize-attributtet vil metoder som er dekorert med TestCleanup, bli utført ved ferdigstillelsen av hver test.
Setup og Teardown Flow
Følgende kode viser strømmen av fixtur og testoppsett og teardown i forhold til de faktiske testene:
Kjører denne monteringen resulterer i følgende feilsøkingsspor:
Fixture Setup. Test Setup. Test A. Test Teardown. Test Setup. Test B. Test Teardown. Fixture Teardown.
Som illustrert i det forrige eksempel, blir fixturen initialisert-deretter for hver test utføres testoppsettet og teardown-koden, etterfulgt av fixtur-teardown på enden.
Mindre hyppig brukte attributter
Følgende avsnitt beskriver mindre vanlige attributter.
AssemblyInitialize / AssemblyCleanup
Metoder dekorert med dette attributtet må være statiske og utføres når montering er lastet. Dette ber om spørsmålet - hva om forsamlingen har mer enn en testarmatur?
Hvis du prøver dette, mislykkes testmaskinen til å kjøre noen enhetstester, rapportering:
"UTA013: UnitTestExamplesVS2008.Fixture2: Kan ikke definere mer enn én metode med AssemblyInitialize attributtet inne i en enhet."
Derfor kan bare én AssemblyInitialize og One AssemblyCleanup-metoden eksistere for en montering, uavhengig av antall testarmaturer i den samlingen. Det anbefales derfor at ingen egentlige tester legges inn i klassen som definerer disse metodene:
Hvis du legger til ignoreringsattributtet til en metode, kan du merke at Visual Studio fortsatt kjører testen. Det er nødvendig å fjerne testbufferen for Visual Studio for å hente endringen. En måte å gjøre dette på er å rense løsningen og gjenoppbygge den.
Eieren
Brukt til rapporteringsformål, beskriver denne attributtet personen som er ansvarlig for enhetstestmetoden.
DeploymentItem
Hvis enhetstester blir kjørt i en egen distribusjonsmappe, kan dette attributtet brukes til å spesifisere filer som en testklasse eller testmetode krever for å kunne kjøre. Du kan angi filer eller mapper for å kopiere til distribusjonsmappen og eventuelt angi målbanen i forhold til distribusjonsmappen.
Beskrivelse
Brukt til rapportering, gir dette attributtet en beskrivelse av testmetoden. Merkelig, dette attributtet er bare tilgjengelig på testmetoder og er ikke tilgjengelig på testklasser.
HostType
For testmetoder brukes denne egenskapen til å spesifisere verten som enhetstesten skal kjøre inn.
Prioritet
Denne egenskapen brukes ikke av testmotoren, men kan brukes, via refleksjon, av din egen testkode. Bruken av dette attributtet er tvilsomt.
WorkItem
Hvis du bruker Team Foundation Server (TFS), kan du bruke dette attributtet på en testmetode for å angi arbeidselement ID som er tildelt av TFS til den spesifikke enhetstesten.
CssIteration / CssProjectStructure
Disse to attributter brukes i forhold til TeamBuild og TestManagementService og lar deg spesifisere en prosjektherreasjon som testmetoden tilsvarer.
Parameterisert testing med DataSource-attributten
Microsofts enhetstestmotor støtter CSV-, XML- eller database datakilder for parameterisert testing. Dette er ikke akkurat ekte parameterisert testing (se hvordan NUnit implementerer parameterisert testing) fordi parametrene ikke sendes til enhetstestmetoden, men må hentes ut fra datakilden og sendes til testmetoden. Imidlertid er muligheten til å laste testdata til en DataTable fra en rekke kilder, nyttig for kjøringstestautomatisering.
CSV datakilde
En tekstfil med komma-separert verdi kan brukes til en datakilde:
[TestClass] offentlig klasse DataSourceExamples public TestContext TestContext get; sett; [TestMethod] [DataSource ("Microsoft.VisualStudio.TestTools.DataSource.CSV", "C: \\ temp \\ csvData.txt", "csvData # txt", DataAccessMethod.Sequential)] offentlig tomgang CsvDataSourceTest () int n = Convert.ToInt32 (TestContext.DataRow ["Numerator"]); int d = Convert.ToInt32 (TestContext.DataRow ["Neminator"]); int r = Konverter.ToInt32 (TestContext.DataRow ["ExpectedResult"]); Debug.WriteLine ("n =" + n + ", d =" + d + ", r =" + r);
Det resulterer i følgende utgang:
n = 10, d = 5, r = 2 n = 20, d = 5, r = 4 n = 33, d = 3, r = 11
Vær oppmerksom på at testresultatvinduet ikke viser parameterløpene (kontrast dette til NUnit):
Parameteriserte testresultater
Det er imidlertid åpenbare fordeler ved ikke å vise hver testkombinasjon, spesielt for store datasett.
XML-datakilde
Gitt en XML-fil som:
et eksempel på bruk av en XML-datakilde for en enhetstest er:
[TestMethod] [DataSource ("Microsoft.VisualStudio.TestTools.DataSource.XML", "C: \\ temp \\ xmlData.xml", "Row", DataAccessMethod.Sequential)] offentlig tomgang XmlDataSourceTest () int n = Konverter .ToInt32 (TestContext.DataRow [ "Teller"]); int d = Convert.ToInt32 (TestContext.DataRow ["Neminator"]); int r = Konverter.ToInt32 (TestContext.DataRow ["ExpectedResult"]); Debug.WriteLine ("n =" + n + ", d =" + d + ", r =" + r);
Merk at annet enn datakildeattributtparametrene, testkoden er den samme.
Database Datakilde
En databasetabell kan også brukes som datakilde. Gitt et bord som:
Databasetabell som datakilde
og data:
Databasetestdata
Et eksempel på testmetode som bruker disse dataene ser ut som:
[TestMethod] [DataSource ("System.Data.SqlClient", "Datakilde = INTERACX-HP; Initial Catalog = UnitTesting; Integrert Security = True"; "DivideTestData"; DataAccessMethod.Sequential)] offentlig tomgang XmlDataSourceTest () int n = Konverter.ToInt32 (TestContext.DataRow ["Numerator"]); int d = Convert.ToInt32 (TestContext.DataRow ["Neminator"]); int r = Konverter.ToInt32 (TestContext.DataRow ["ExpectedResult"]); Debug.WriteLine ("n =" + n + ", d =" + d + ", r =" + r);
Igjen, vær oppmerksom på at testmetoden selv er den samme. Det eneste vi har gjort her, er å endre DataSource-definisjonen.
TestProperty Attribut
MSDN-dokumentasjonen for dette attributtet illustrerer å deklarere et TestProperty-navnverdierpar og deretter, ved å bruke refleksjon, anskaffe navnet og verdien. Dette ser ut til å være en ubarmhjertig måte å skape parameteriserte tester på.
Koden, som er beskrevet på Craig Anderas blogg, for å bruke TestProperty-attributtet til å parameterisere testinitialiseringsprosessen, påvirker ikke TestContext.Properties-samlingen på Visual Studio 2008 eller Visual Studio 2012.