Unit Testing Succinctly Hvordan fungerer Unit Testing?

Dette er et utdrag fra Unit Testing Succinctly eBook, av Marc Clifton, gitt vennlig av Syncfusion.

En enhetstestmotor på et reflekterende språk (for eksempel et. NET-språk) har tre deler:

  • Laster sammen forsamlinger som inneholder testene.
  • Bruk refleksjon for å finne testmetodene.
  • Påkalle metodene og validere resultatene.

Denne artikkelen inneholder kodeeksempler på hvordan dette virker, å sette sammen en enkelhets testmotor. Hvis du ikke er interessert i undersøkelsen av enhetstestmotorer, er du velkommen til å hoppe over denne artikkelen.

Koden her antar at vi skriver en testmotor mot Visual Studio-enhetstestattributtene som er definert i Microsoft.VisualStudio.QualityTools.UnitTestFramework-samlingen. Andre enhetstestmotorer kan bruke andre attributter til samme formål.

Laster inn samlinger

Arkitektonisk bør enhetstestene dine enten være plassert i en separat enhet fra koden som testes, eller som minimum bør bare inkluderes i forsamlingen dersom den er sammensatt i "Feilsøkingsmodus". Fordelen ved å sette enhetstestene i en separat enhet er at du også kan prøve enhetens ikke-feilsøking, optimalisert produksjonsversjon av koden.

Når det er sagt, er det første trinnet å laste enheten:

statisk bool LoadAssembly (string assemblyFilename, out Assembly assy, ​​utstrengsproblem) bool ok = true; problem = String.Empty; assy = null; prøv assy = Assembly.LoadFile (assemblyFilename);  fangst (Unntak ex) issue = "Feil lasting av samling:" + ex.Message; ok = false;  gå tilbake ok; 

Vær oppmerksom på at profesjonelle enhetstestmotorer laster sammen enheter i et eget applikasjonsdomene slik at montering kan lastes ut eller lastes om uten å starte testmaskinen på nytt. Dette gjør det også mulig å rekompilere enhetstestmontering og avhengige enheter uten å først slå av testmaskinen først.

Bruke refleksjon for å finne enhetstestmetoder

Det neste trinnet er å reflektere over forsamlingen for å identifisere klassene som er utpekt som en "test fixture" og innenfor disse klassene, for å identifisere testmetodene. Et grunnleggende sett med fire metoder støtter kravene til minimale enhetstestmotor, oppdagelsen av testarmaturer, testmetoder og unntakshåndteringsegenskaper:

///  /// Returnerer en liste over klasser i den angitte enheten som har et "TestClass" -attributt. ///  statisk IEnumerable GetTestFixtures (Assembly Assy) return assy.GetTypes (). Hvor (t => t.GetCustomAttributes (typeof (TestClassAttribute), false) .Length == 1);  ///  /// Returnerer en liste over metoder i testfestet som er dekorert med "TestMethod" -attributtet. ///  statisk IEnumerable GetTestMethods (Type testFixture) return testFixture.GetMethods (). Hvor (m => m.GetCustomAttributes (typeof (TestMethodAttribute), false) .Length == 1);  ///  /// Returnerer en liste over spesifikke attributter som kan dekorere metoden. ///  statisk IEnumerable GetMethodAttributes(MethodInfo metode) return method.GetCustomAttributes (typeof (AttrType), false) .Cast();  ///  /// Returnerer sant hvis metoden er dekorert med et "ExpectedException" -attributt mens unntakstype er det forventede unntaket. ///  statisk bool IsExpectedException (MethodInfo metode, Exception expectedException) Type expectedExceptionType = expectedException.GetType (); returnere GetMethodAttributes(metode). Hvor (attr => attr.ExceptionType == expectedExceptionType) .Count ()! = 0; 

Innkallingsmetoder

Når denne informasjonen er utarbeidet, påkaller motoren testmetodene i en prøvefeltboks (vi vil ikke at enhetens testmotor selv krasjer):

statisk tomrum RunTests (Type testFixture, Action resultat) IEnumerable testmetoder = GetTestMethods (testFixture); if (testMethods.Count () == 0) // Ikke gjør noe hvis det ikke finnes noen testmetoder. komme tilbake;  object inst = Activator.CreateInstance (testFixture); foreach (MethodInfo mi i testmetoder) bool pass = false; prøv // Testmetoder har ikke parametere. mi.Invoke (inst, null); pass = true;  fangst (Unntak ex) pass = IsExpectedException (mi, ex.InnerException);  Endelig resultat (testFixture.Name + "." + mi.Name + ":" + (pass? "Pass": "Feil")); 

Til slutt kan vi sette denne koden sammen i en enkel konsollapplikasjon som tar enhetstestsamlingen som parameter resulterer i en brukbar, men enkel motor:

bruker system; bruker System.Collections.Generic; bruker System.IO; bruker System.Linq; bruker System.Reflection; bruker System.Text; bruker Microsoft.VisualStudio.TestTools.UnitTesting; namespace SimpleUnitTestEngine class Program static void Main (streng [] args) string issue; hvis (! VerifyArgs (args, ut problem)) Console.WriteLine (problem); komme tilbake;  Montering assy; hvis (! LoadAssembly (args [0], ut assy, ​​ut problem)) Console.WriteLine (issue); komme tilbake;  IEnumerable testFixtures = GetTestFixtures (assy); foreach (Type testFixture i testFixtures) RunTests (testFixture, t => Console.WriteLine (t));  statisk bool VerifyArgs (streng [] args, utstrengsproblem) bool ok = true; problem = String.Empty; hvis (args.Length! = 1) issue = "Bruk: SimpleUnitTestEngine "; ok = false; else string assemblyFilename = args [0]; hvis (! File.Exists (assemblyFilename)) issue =" Filnavnet "" + args [0] + "'eksisterer ikke." = false; return ok; ... resten av koden ... 

Resultatet av å kjøre denne enkle testmotoren vises i et konsollvindu, for eksempel:

Våre enkle testmotorkonsolresultater