UTT #4 - Test af private metoder

by Jesper juni 28, 2008 08:52

Der er basalt set 4 måder at teste private metoder på:

  1. Marker metoden som internal
  2. Indlejret testklasse
  3. Refleksion
  4. Undgå det

1 – Markerer man metoden som internal, og samtidig angiver test-assembly'en som ven, kan man få adgang til den fra test metoderne. Metoden er brugbar, men man bryder man indkapslingen. Der er godt nok ikke andre assembly'er der kan tilgå metoderne, men internt, har man åbnet adgangen fra alle andre klasser. Det lugter lidt...
Man markerer sin assembly som ven, ved at føje en InternalsVisibleToAttribute til assembly'en. Det gøres nemmest i AssemblyInfo.cs filen:

[code=csharp] [assembly: InternalsVisibleTo("myTest")] [/code]

2 – Man kan indlejre sin testklasse I selve klassen, som man ønsker at teste. På den måde, har man fuld adgang til alle medlemmer. Det indebærer selvfølgelig at man får spredt sine tests ud over det hele, og man kan få store problemer med overskueligheden. Hvad er test og hvad er produktion?

3 – Man kan bruge refleksion, og Invoke metoden med MethodInfo klassen.

[code=csharp] [TestMethod] public void Test_privat_metode() { MyClass m = new MyClass(); MethodInfo mi = typeof(MyClass).GetMethod("GetMessage", BindingFlags.NonPublic | BindingFlags.Instance); object value = mi.Invoke(m, new object[] { 1 }); Assert.AreEqual("Hello!", value); } [/code]

Fordelen ved refleksion er: at man undgår at bryde indkapslingen, og at man undgår at fylde sin produktionskode med test-kode. Ulempen er at man få noget følsom test-kode, da man jo angiver metodenavne i strenge. En RenameMethod refactoring, vil afstedkomme at alle tests af den metode vil fejle.

4 – Undgå det. Man skal aldrig bryde indkapsling for at kunne teste. En klasses funktionalitet, bør kunne testes gennem dens offentlige interface. Husk på at testen skal teste funktionalitet, og ikke implementering. Hvis ikke, er det sandsynligvis en code-smell, der forsøger at fortælle dig noget. F.eks. at du skal uddrage en ny klasse til at dække funktionaliteten.
Der er selvfølgelig steder, hvor man bare er nød til at bryde denne indkapsling, for at kunne foretage sine tests, men jeg mener at disse tilfælde er uhyre sjældne, og bør afstedkomme en nærmere undersøgelse.

Der er selvfølgelig ikke et rigtigt svar til hvordan/om man skal teste private metoder. Det kommer i høj grad an på situationen. Jeg hælder nok selv mest til metode 4...

Carry On Implementing…

Tags:

Kommentarer

03-07-2008 05:21:31 #

Brian

Du kan med fordel bruge PrivateObject og PrivateType der indkapsler det nødvendige reflection-kode. Se msdn.microsoft.com/.../....unittesting(VS.80).aspx

Brian Denmark

03-07-2008 07:20:34 #

Jesper

Brian>Smart - det havde jeg ikke set. Det vil ændre mit eks. til følgende:

[code=csharp]MyClass m = new MyClass();
PrivateObject po = new PrivateObject(m);
object value = po.Invoke("GetMessage", 1);

Assert.AreEqual("Hello!", value);
[/code]
Måske ikke i dette tilfælde den helt store gevinst, men jeg kan se mulighedderne. Det ændre dog ikke ved at man skal ændre i sine tests, hvis man f.eks. omdøber metoden.
Spørgsmålet er bare om man bør teste private medlemmer. I langt de fleste tilfælde, er et sådan behov, et tegn på at en klasse er ved at 'bryde ud' af den eksisterende kode.

Jesper Denmark

07-07-2008 22:35:17 #

Brian

Ja reflection har den ulempe, men det er prisen for at slippe forbi compilerens check. Et alternativ (som dog ikke er hverken lettere eller kønnere) er at lave en metode med emit og tilknytte den en eksisterende type - derved får den adgang til private members.

Brian Denmark

08-07-2008 01:35:13 #

Jesper

Brian> Det er jo mere eller mindre det samme som at markerer metoden intern. Det bryder bare med indkapslingsprincippet. Jeg hælder stadig til min metode 4 - Undlad at teste interne metoder Wink

Jesper Denmark

Kommentarerne er lukkede

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen | Modified by Mooglegiant

About

Mit navn er Jesper Jensen, og jeg arbejder til dagligt som web-udvikler hos DGI, hvor mit speciale er klientside applikationer. Før det var jeg nogle år i robotbranchen, hvor jeg arbejdede med 3D simulering og system koordinering. Jeg elsker webudvikling, og specielt JavaScript har min interesse. Jeg har blogget om mine oplevelser med udvikling siden 2004

Calendar

<<  september 2010  >>
mationtofr
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar

RecentComments

Comment RSS