tillvägagångssätt 1: Testa inte privata metoder

testa privata metoder med JUnit och SuiteRunner
av Bill Venners
Maj 24, 2004
sammanfattning

den här artikeln jämför fyra olika metoder för att testa privata metoder i Java-klasser.

min allra första användning av JUnit var att bygga ett överensstämmelsetestkit för ServiceUI API . Syftet med ett överensstämmelsetestpaket är att säkerställa att alternativa implementeringar av samma API är kompatibla med API: s specifikation. Eftersom en API-specifikation endast definierar API: s offentliga gränssnitt, inte API: s implementering, utövar ett överensstämmelsestest endast det offentliga gränssnittet. Med andra ord är ett överensstämmelsetest ett ”svart låda” – test. Det behandlar API som testas som en svart låda, vars externa gränssnitt kan ses, men vars interna implementering inte kan. Ett överensstämmelsetest av ett Java API behöver därför bara komma åt de offentliga medlemmarna i paketen och klasserna som testas. Det finns inget behov av att komma åt paketnivå, skyddade eller privata medlemmar.

när jag senare tillämpade JUnit på uppgiften att skriva faktiska enhetstester, i motsats till överensstämmelsestester, fann jag mig själv att skriva white box test—test som använder kunskap om det interna genomförandet av paketen och klasserna som testas. Medan jag bara ville testa offentliga metoder i mina överensstämmelsetester, ville jag skriva enhetstester för paketåtkomst och ibland privata metoder samt offentliga metoder.

Daniel Steinberg visade mig den vanliga JUnit-tekniken att använda parallella källkodsträd, vilket gjorde det möjligt för mig att placera testklasser i samma paket som klasserna som testas, men behåll dem i en annan katalog. Detta gav en ren separation av test-och produktionskod. Genom att placera båda källträd i CLASSPATH kunde mina testklasser komma åt paketnivåmetoder och klasser i paketet som testas. Detta lämnade mig fortfarande med problemet med att testa privata metoder.

när jag frågade Daniel om att testa privata metoder föreslog han försiktigt att jag testar de privata metoderna indirekt genom att testa paketåtkomsten och offentliga metoder som kallar de privata. Det här svaret uppfyllde mig inte riktigt, för ibland kände jag verkligen uppmaningen att direkt testa en privat metod. Min första lösning var att bara göra sådana privata metoder paketåtkomst, vilket gjorde det möjligt för mig att testa dem direkt med JUnit från testklasserna i samma paket i det parallella källkodsträdet. Detta fungerade bra, men fick mig att känna mig lite smutsig på något sätt. Även om jag i allmänhet upptäckte att jag tänkte på hur man designar gränssnitt så att de enkelt kunde testas hjälpte mig att designa bättre gränssnitt, i det här fallet kände jag att jag gjorde designen lite sämre för att göra den testbar.

när jag senare slutade delta i skapandet av vad Frank Sommers, Matt Gerrans, och jag så småningom släppte som Artima SuiteRunner , lovade jag att jag skulle göra testningen av privata metoder enklare i SuiteRunner än i JUnit. Men efter att ha undersökt de olika metoderna för att testa privata metoder bestämde jag mig för att inte göra något speciellt i SuiteRunner för att stödja testning av privata metoder. Så oavsett om du använder JUnit eller SuiteRunner, du har samma fyra grundläggande metoder för att testa privata metoder:

  • testa inte privata metoder.
  • ge åtkomst till metodpaketet.
  • använd en kapslad testklass.
  • använd reflektion.

i den här artikeln kommer jag att diskutera dessa fyra metoder för att testa privata metoder i Java. Jag kommer att titta på fördelarna och nackdelarna med var och en och försöka belysa när det är vettigt att använda varje tillvägagångssätt.

som jag nämnde i inledningen hörde jag först rådet att undertrycka mina tillfälliga uppmaningar att testa privata metoder från Daniel Steinberg. Men Daniel är inte bara källan till detta råd som jag har stött på. Det verkar vara en gemensam attityd i Java-samhället. Till exempel säger JUnit FAQ:

att testa privata metoder kan vara en indikation på att dessa metoder bör flyttas till en annan klass för att främja återanvändbarhet.

Charles Miller uttryckte en liknande synvinkel i sin blogg :

om du har en grundlig serie tester för en klass exponerade (icke-privata) gränssnitt, bör dessa tester, till sin natur, Kontrollera att någon privat metod inom klassen fungerar också. Om detta inte är fallet, eller om du har en privat metod så komplex att den måste testas ur sammanhanget för sina offentliga uppringare, skulle jag betrakta det som en kodlukt.

och Dave Thomas och Andy Hunt skriver i sin bok Pragmatic Unit Testing:

i allmänhet vill du inte bryta någon inkapsling för att testa (eller som mamma brukade säga, ”Utsätt inte dina meniga!”). För det mesta bör du kunna testa en klass genom att utöva sina offentliga metoder. Om det finns betydande funktionalitet som är dold bakom privat eller skyddad åtkomst, kan det vara ett varningstecken på att det finns en annan klass där som kämpar för att komma ut.

jag tror på allt detta råd. För det mesta kan privata metoder testas mest effektivt via tillvägagångssätt 1, indirekt genom att testa paketnivå, skyddade och offentliga metoder som kallar dem. Men oundvikligen, vissa människor i vissa situationer kommer att känna att direkt testa en privat metod är rätt sak att göra.

i mitt fall tenderar jag att skapa många privata verktygsmetoder. Dessa verktygsmetoder gör ofta ingenting med instansdata, de fungerar bara på de godkända parametrarna och returnerar ett resultat. Jag skapar sådana metoder för att göra anropsmetoden lättare att förstå. Det är ett sätt att hantera komplexiteten i genomförandet av klassen. Nu, om jag extraherar den privata metoden ur en metod som redan fungerar och har bra enhetstesttäckning, kommer de befintliga enhetstesterna sannolikt att räcka. Jag behöver inte skriva fler enhetstester bara för den privata metoden. Men om jag vill skriva den privata metoden före sin anropsmetod, och jag vill skriva enhetstesterna innan jag skriver den privata metoden, är jag tillbaka till att vilja direkt testa den privata metoden. När det gäller privata verktygsmetoder känner jag inte min lust att direkt testa metoderna, som JUnit FAQ uttryckte det, ”en indikation på att dessa metoder bör flyttas till en annan klass för att främja återanvändbarhet.”Dessa metoder behövs egentligen bara i den klass där de bor, och kallas faktiskt ofta bara med en annan metod.

en annan anledning till att jag ibland känner lust att testa privata metoder direkt är att jag tenderar att tänka på enhetstestning som att hjälpa mig att uppnå ett robust system genom att bygga det systemet av robusta delar. Varje del är en” enhet ”för vilken jag kan skriva” enhetstester.”Enhetstesterna hjälper mig att säkerställa att varje enhet fungerar korrekt, vilket i sin tur hjälper mig att bygga ett system som fungerar korrekt som helhet. Den primära enheten jag tror när det gäller programmering i Java är klassen. Jag bygger system av klasser, och enhetstester ger mig förtroende för att mina klasser är robusta. Men till viss del känner jag också på samma sätt om de privata metoder som jag komponerar paketåtkomst, skyddad och offentliga metoder. Dessa privata metoder är enheter som kan testas individuellt. Sådana enhetstester ger mig förtroende för att de privata metoderna fungerar korrekt, vilket hjälper mig att bygga paketåtkomst, skyddade och offentliga metoder som är robusta.

som jag nämnde i introduktionen var att ge methods package access min första metod för att testa privata metoder med JUnit. Detta tillvägagångssätt fungerar faktiskt bra, men det kommer med en liten kostnad. När jag ser en privat åtkomst specificerare på en metod, det säger mig något jag vill veta—att detta är en del av genomförandet av klassen. Jag vet att jag kan ignorera metoden om jag bara försöker använda klassen från en annan klass i paketet. Jag kunde räkna ut detta om en paketåtkomstmetod genom att titta närmare på namnet, dokumentationen och koden för metoden, men ordet privat kommunicerar detta mycket mer effektivt. Dessutom är det största problemet jag har med detta tillvägagångssätt filosofiskt. Även om jag inte har något emot att ”bryta inkapsling för testningens skull”, som Dave och Andy skulle uttrycka det, känner jag mig inte bra om att bryta inkapsling på ett sätt som ändrar API på paketnivå. Med andra ord, även om jag är ganska entusiastisk att testa icke-offentliga metoder för klasser, dvs att skapa ”white-box” enhetstester, skulle jag hellre API för de klasser som testas, inklusive API på paketnivå, inte ändras för att underlätta dessa tester.

tillvägagångssätt 3: använd en kapslad Testklass

en tredje metod för att testa privata metoder är att bo en statisk testklass i produktionsklassen som testas. Med tanke på att en kapslad klass har tillgång till de privata medlemmarna i sin inneslutande klass, skulle den kunna åberopa de privata metoderna direkt. Den statiska klassen i sig kan vara paketåtkomst, så att den kan laddas som en del av white box-testet.

nackdelen med detta tillvägagångssätt är att om du inte vill att den kapslade testklassen är tillgänglig i din deployment JAR-fil, måste du göra lite extra arbete för att extrahera det. Vissa människor kanske inte gillar att ha testkod blandad i samma fil som produktionskod, även om andra kanske föredrar det tillvägagångssättet.

tillvägagångssätt 4: Använd reflektion

den fjärde metoden för att testa privata metoder föreslogs för mig av Vladimir R. Bossicard, som skrev JUnit Addons . En dag under lunchen upplyste Vladimir mig om att API: n java.lang.reflect inkluderade metoder som gjorde det möjligt för klientkod att kringgå åtkomstskyddsmekanismen för Java virtual machine. Han berättade också för mig att hans JUnit Addons-projekt inkluderade en klass, junitx.util.PrivateAccessor, för att hjälpa till med att använda reflection API för just detta ändamål: att skriva enhetstester som manipulerar privata medlemmar i klasserna som testas. JUnit FAQ pekar på en liknande klass, kallad PrivilegedAccessor, skriven av Charlie Hubbard och Prashant Dhotke.

en fördel med att använda reflektionsmetoden för att testa privata metoder är att det ger en ren separation av testkod och produktionskod. Testerna behöver inte kapslas in i den klass som testas, som i tillvägagångssätt 3. Snarare kan de placeras tillsammans med de andra testerna som utövar klassens paketnivå och offentliga metoder. Dessutom behöver du inte ändra API för klassen som testas. Till skillnad från tillvägagångssätt 2 kan privata metoder förbli privata. Till skillnad från approach 3 behöver du inte lägga till någon extra kapslad klass på paketåtkomstnivå. Den största nackdelen med detta tillvägagångssätt är att testkoden är mycket mer detaljerad eftersom den använder reflection API. Dessutom är refactoring IDEs som Eclipse och IntelliJ vanligtvis inte lika skickliga på att ändra namnen på metoder där de kallas Strings som skickas till metoderna för reflection API. Så om du ändrar namnet på den privata metoden med din refactoring IDE kan du fortfarande behöva göra några ändringar för hand i testkoden.

ett exempel

för att ge ett exempel på en privat metod som enligt min mening förtjänar direkt enhetstestning extraherade jag viss funktionalitet urmain– metoden i klassenorg.suiterunner.Runner.Runner.maintolkar kommandoradsargument och kör en serie tester, eventuellt skjuter upp GUI. Metoden jag extraherade,parseArgsIntoLists, gör en del av arbetet med att analysera kommandoradsargumenten till SuiteRunner-applikationen. Nu, för att testa den offentliga metoden som kallar denna privata metod, skulle jag behöva testamain. Huvud är naturligtvis hela applikationen, vilket gör metoden ganska svår att testa. Jag har faktiskt inget befintligt test förmain.

vid denna tidpunkt kanske du undrar, om jag skrev tester först i stil med testdriven utveckling , Hur slutade jag någonsin att skriva analyskod som inte hade några enhetstester? Huvudskälet är att min testinfektion har kommit i steg. Jag fick faktiskt en enhetstestinfluensa långt innan jag hade hört talas om JUnit eller läs Testinfekterat . Tillbaka när jag byggde Windows-applikationer i C++, till exempel, skulle jag skriva lite kod för att testa en ny implementerad metod, kör sedan den koden och se den exekvera genom att gå igenom metoden som testas med debugger. Denna typ av enhetstestning hjälpte mig att uppnå robusthet, men testerna själva kontrollerade inte för rätt beteende. Jag kontrollerade för rätt beteende själv genom att observera via debugger. Testerna var inte automatiserade, och därför sparade jag dem inte så att de kunde köras igen senare. När jag läste Test Infected såg jag omedelbart värdet av att automatisera testerna och hålla dem runt som ett slags regressionstest efter refactoring, men under lång tid var det inte meningsfullt för mig att skriva testen först. Jag ville skriva testerna efter att jag implementerat funktionaliteten, för det var när jag hade kört testerna med felsökaren. En sekundär anledning till att jag inte skrev tester först när jag utvecklade mycket av SuiteRunner är att jag ville skriva Suiterunners tester med SuiteRunner själv, i ett försök att äta min egen hundmat. Fram till Suiterunners grundläggande API avgjorde, hade jag inte testverktyget som jag ville använda för att skriva testen.

sedan dess har dock testviruset tagit ett starkare grepp om mig, och jag föredrar nu att skriva enhetstester först för det mesta. Jag föredrar att skriva tester först inte så mycket eftersom jag tycker att jag slutar med renare mönster, vilket vanligtvis främjas som den största fördelen med testdriven utveckling. Snarare föredrar jag att skriva tester först eftersom jag tycker att ofta om jag dyker in i koden under tryck, med avsikt att jag ska skriva testet senare, blir testet faktiskt aldrig skrivet. SuiteRunner själv har väldigt få enhetstester vid denna tidpunkt av just den anledningen. Här är parseArgsIntoLists – metoden:

 private static void parseArgsIntoLists(String args, List runpathList, List reportersList, List suitesList) { if (args == null || runpathList == null || reportersList == null || suitesList == null) { throw new NullPointerException(); } for (int i = 0; i < args.length; i++) { if (args.startsWith("-p")) { runpathList.add(args); runpathList.add(args); ++i; } else if (args.startsWith("-g")) { reportersList.add(args); } else if (args.startsWith("-o")) { reportersList.add(args); } else if (args.startsWith("-e")) { reportersList.add(args); } else if (args.startsWith("-f")) { reportersList.add(args); reportersList.add(args); ++i; } else if (args.startsWith("-r")) { reportersList.add(args); reportersList.add(args); ++i; } else if (args.startsWith("-s")) { suitesList.add(args); do { ++i; suitesList.add(args); } while (i + 1 < args.length); } else { throw new IllegalArgumentException("Unrecognized argument: " + args); } } }

kommandoraden för SuiteRunner innehåller tre typer av information som används av SuiteRunner för att köra tester: runpath, reportrar och sviter. Metoden parseArgsIntoLists går bara igenom argumenten som skickas som en array av String s och placerar varje argument i en av listorna, runpathList, reportersList och suitesList.

innan jag skriver ett test för denna privata metod, skulle jag fråga om min uppmaning att skriva detta enhetstest representerar en kodlukt, som Charles Miller uttryckte det i sin blogg? Indikerar det att parseArgsIntoLists ska flyttas till en annan klass för att främja återanvändbarhet, som JUnit FAQ föreslår? Skulle Dave och Andy säga att det är ett varningstecken på att det finns en annan klass där som kämpar för att komma ut? Tja, kanske. Jag kunde medvetet skapa en ArgumentsParser – klass som bara innehåller några statiska metoder som utför analysarbetet. Både ArgumentsParser – klassen och metoderna som den innehåller kan vara paketåtkomst, vilket skulle göra dem lätta att testa. Men det känns bara inte rätt för mig. Dessa metoder kallas endast av Runner.main. De känns helt klart som privata metoder för mig. Den enda anledningen till att jag skulle flytta dem till en ArgumentsParser – klass är att kunna testa dem. Jag skulle faktiskt använda tillvägagångssätt nummer 2: gör det privata metodpaketet åtkomst.

istället för detta exempel bestämde jag mig för att ta tillvägagångssätt nummer 4 och använda reflektion. Jag tittade på både Vladimir Bossicard ’s junitx.utils.PrivateAccessor och Charlie Hubbard och Prashant Dhotke’ s PrivilegedAccessor, men bestämde mig för att ingen av dem hjälpte mig riktigt som jag ville. För det första har dessa klasser båda förmågan att testa fält för att se till att de är korrekt inställda. Hittills har jag aldrig känt någon lust att direkt komma åt privata fält från enhetstester. Jag vill bara kunna testa privata verktygsmetoder. Det största problemet jag hade med dessa två klasser är dock hur de hanterade de undantag som kan kastas när man försöker åberopa den privata metoden via reflektion. Varje klass har en eller flera metoder vars jobb det är åberopa en metod med reflektion. PrivilegedAccessor’s två invokeMethod metoder skickar något undantag tillbaka till sin uppringare, inklusive tre kontrollerade undantag som deklareras i kastklausulen: NoSuchMethodException, IllegalAccessException och InvocationTargetException. Däremot fångar PrivateAccessortvå invoke metoder InvocationTargetException och extraherar och kastar målundantaget, det faktiska undantaget som kastas av den åberopade metoden. Det fångar sedan något annat undantag och kastar NoSuchMethodException. Jag tyckte inte om att den som ringer PrivilegedAccessor.invokeMethod alltid skulle behöva hantera de tre kontrollerade undantagen, för jag tänkte att det allmänna sättet att hantera något undantag skulle vara att låta testet misslyckas. Jag var också oroad över att PrivateAccessor.invoke kastade bort potentiellt användbar stackspårningsinformation i sin undantagshanteringspolicy. Vad jag verkligen ville ha var en metod som försökte åberopa en privat metod med reflektion, som lindade alla kastade undantag förutom InvocationTargetException i en okontrollerad TestFailedException. För det mesta skulle detta undantag leda till att testet misslyckas. I tester som förväntade sig att ett undantag skulle kastas kunde undantaget i InvocationTargetException extraheras och testas för korrekthet.

därför skrev jag invokeStaticMethod. Samtalet setAccessible(true) är det som gör att den privata metoden kan åberopas utanför klassen. En motsvarande invokeStaticMethod implementering för användning med JUnit skulle kasta AssertionFailedErrorsnarare än TestFailedException. Här är koden:

 private static void invokeStaticMethod(Class targetClass, String methodName, Class argClasses, Object argObjects) throws InvocationTargetException { try { Method method = targetClass.getDeclaredMethod(methodName, argClasses); method.setAccessible(true); method.invoke(null, argObjects); } catch (NoSuchMethodException e) { // Should happen only rarely, because most times the // specified method should exist. If it does happen, just let // the test fail so the programmer can fix the problem. throw new TestFailedException(e); } catch (SecurityException e) { // Should happen only rarely, because the setAccessible(true) // should be allowed in when running unit tests. If it does // happen, just let the test fail so the programmer can fix // the problem. throw new TestFailedException(e); } catch (IllegalAccessException e) { // Should never happen, because setting accessible flag to // true. If setting accessible fails, should throw a security // exception at that point and never get to the invoke. But // just in case, wrap it in a TestFailedException and let a // human figure it out. throw new TestFailedException(e); } catch (IllegalArgumentException e) { // Should happen only rarely, because usually the right // number and types of arguments will be passed. If it does // happen, just let the test fail so the programmer can fix // the problem. throw new TestFailedException(e); } }

därefter skapade jag en bekvämlighetsmetod som åberopar den speciella privata metoden jag ville testa:

 private static void invokeParseArgsIntoLists(String args, List runpathList, List reportersList, List suitesList) throws InvocationTargetException { // Purposely pass null values to the method, to make sure it throws // NullPointerException Class argClasses = {String.class, List.class, List.class, List.class }; Object argObjects = {args, runpathList, reportersList, suitesList }; invokeStaticMethod(Runner.class, "parseArgsIntoLists", argClasses, argObjects); }

äntligen kunde jag skriva tester mot den privata metoden utan för mycket överskott, så här:

 public void testParseArgsIntoLists() throws InvocationTargetException { String args = new String; List runpathList = new ArrayList(); List reportersList = new ArrayList(); List suitesList = new ArrayList(); try { invokeParseArgsIntoLists(null, runpathList, reportersList, suitesList); fail(); } catch (InvocationTargetException e) { // throw the InvocationTargetException unless the target // exception is NullPointerException, which is expected Throwable targetException = e.getTargetException(); if (!(targetException instanceof NullPointerException)) { throw e; } } try { invokeParseArgsIntoLists(args, null, reportersList, suitesList); fail(); } catch (InvocationTargetException e) { // throw the InvocationTargetException unless the target // exception is NullPointerException, which is expected Throwable targetException = e.getTargetException(); if (!(targetException instanceof NullPointerException)) { throw e; } } try { invokeParseArgsIntoLists(args, runpathList, null, suitesList); fail(); } catch (InvocationTargetException e) { // throw the InvocationTargetException unless the target // exception is NullPointerException, which is expected Throwable targetException = e.getTargetException(); if (!(targetException instanceof NullPointerException)) { throw e; } } try { invokeParseArgsIntoLists(args, runpathList, reportersList, null); fail(); } catch (InvocationTargetException e) { // throw the InvocationTargetException unless the target // exception is NullPointerException, which is expected Throwable targetException = e.getTargetException(); if (!(targetException instanceof NullPointerException)) { throw e; } } args = new String; args = "-p"; args = "\"mydir\""; args = "-g"; args = "-f"; args = "test.out"; args = "-s"; args = "MySuite"; runpathList.clear(); reportersList.clear(); suitesList.clear(); invokeParseArgsIntoLists(args, runpathList, reportersList, suitesList); verify(runpathList.size() == 2); verify(runpathList.get(0).equals(args)); verify(runpathList.get(1).equals(args)); verify(reportersList.size() == 3); verify(reportersList.get(0).equals(args)); verify(reportersList.get(1).equals(args)); verify(reportersList.get(2).equals(args)); verify(suitesList.size() == 2); verify(suitesList.get(0).equals(args)); verify(suitesList.get(1).equals(args)); args = new String; args = "-p"; args = "\"mydir\""; args = "-e"; args = "-o"; args = "-r"; args = "MyCustomReporter"; args = "-s"; args = "MySuite"; args = "MyOtherSuite"; runpathList.clear(); reportersList.clear(); suitesList.clear(); invokeParseArgsIntoLists(args, runpathList, reportersList, suitesList); verify(runpathList.size() == 2); verify(runpathList.get(0).equals(args)); verify(runpathList.get(1).equals(args)); verify(reportersList.size() == 4); verify(reportersList.get(0).equals(args)); verify(reportersList.get(1).equals(args)); verify(reportersList.get(2).equals(args)); verify(reportersList.get(3).equals(args)); verify(suitesList.size() == 3); verify(suitesList.get(0).equals(args)); verify(suitesList.get(1).equals(args)); verify(suitesList.get(2).equals(args)); args = new String; args = "-p"; args = "\"serviceuitest-1.1beta4.jar myjini http://myhost:9998/myfile.jar\""; args = "-g"; args = "-s"; args = "MySuite"; args = "MySecondSuite"; args = "MyThirdSuite"; args = "MyFourthSuite"; args = "MyFifthSuite"; args = "MySixthSuite"; runpathList.clear(); reportersList.clear(); suitesList.clear(); invokeParseArgsIntoLists(args, runpathList, reportersList, suitesList); verify(runpathList.size() == 2); verify(runpathList.get(0).equals(args)); verify(runpathList.get(1).equals(args)); verify(reportersList.size() == 1); verify(reportersList.get(0).equals(args)); verify(suitesList.size() == 7); verify(suitesList.get(0).equals(args)); verify(suitesList.get(1).equals(args)); verify(suitesList.get(2).equals(args)); verify(suitesList.get(3).equals(args)); verify(suitesList.get(4).equals(args)); verify(suitesList.get(5).equals(args)); verify(suitesList.get(6).equals(args)); }

slutsats

tillvägagångssätt 1, Testa privata metoder indirekt genom att testa paketnivå, skyddade och offentliga metoder som kallar dem, kommer ofta att vara det bästa tillvägagångssättet. I de fall där du verkligen vill testa privata metoder direkt, med hjälp av reflektion för att testa privata metoder, även om det är ganska besvärligt, ger den renaste separationen av testkod från produktionskod och minst påverkan på produktionskoden. Men om du inte har något emot att göra de specifika privata metoderna du vill testa paketåtkomst kan du använda approach 2. Eller om du inte har något emot att placera en kapslad testklass i din produktionsklass under test, skulle approach 3 åtminstone låta dig hålla de privata metoderna privata.

det finns inget perfekt svar. Men om du antar tillvägagångssätt 4 kommer du i slutändan att sluta med en handfull metoder som invokeStaticMethod som du kan återanvända. När du skriver en bekvämlighetsmetod, som invokeParseArgsIntoLists, för en privat metod, kan du skriva tester mot den privata metoden utan stora svårigheter.

resurser

1. ServiceUI API definierar ett standardiserat sätt att koppla användargränssnitt till Jini-tjänster:
http://www.artima.com/jini/serviceui/index.html

2. Daniel Steinberg är för närvarande chefredaktör för Java.NET:
http://www.java.net/

3. Artima SuiteRunner är en fri öppen källkod testning verktygslåda och JUnit runner:
http://www.artima.com/suiterunner/index.html

4.JUnit FAQ fråga om att testa privata metoder:
http://junit.sourceforge.net/doc/faq/faq.htm#tests_10

5. Testa privata metoder( gör det inte), ett blogginlägg av Charles Miller:
http://fishbowl.pastiche.org/2003/03/28/testing_private_methods_dont_do_it

6. Andy Hunt och Dave Thomas är författarna till Pragmatic Unit Testing, som finns i Pragmatic Store.

7. JUnit Addons är en samling hjälparklasser för JUnit skapad av Vladimir R. Bossicard:
http://sourceforge.net/projects/junit-addons

PrivateAccessor är klassen från JUnit Addons som underlättar testning av privata medlemmar:
http://junit-addons.sourceforge.net/junitx/util/PrivateAccessor.html

9.PrivilegedAccessor klass, som du kan använda för att komma åt privata medlemmar:
http://groups.yahoo.com/group/junit/files/src/PrivilegedAccessor.java

10. Testdriven utveckling genom Exempel, av Kent Beck, beskriver test-första tekniken:
http://www.amazon.com/exec/obidos/ASIN/0321146530/

11. Test Infected, av Kent Beck och Erich Gamma, introducerade JUnit till världen:
http://junit.sourceforge.net/doc/testinfected/testing.htm

enhetstestning privata metoder, ett blogginlägg om nUnit av Ted Graham:
http://weblogs.asp.net/tgraham/archive/2003/12/31/46984.aspx

undergräva Java: s åtkomstskydd för enhetstestning, en O ’ Reilly OnJava.com artikel av Ross Burton:
http://www.onjava.com/pub/a/onjava/2003/11/12/reflection.html

klass RunnerSuite, från vilken kodavsnitten i den här artikeln togs, visas i sin helhet här:
http://www.artima.com/suiterunner/privateExample.html

varför vi Refactored JUnit
http://www.artima.com/suiterunner/why.html

Artima SuiteRunner handledning, bygga överensstämmelse och enhetstester med Artima SuiteRunner:
http://www.artima.com/suiterunner/tutorial.html

komma igång med Artima SuiteRunner, hur man kör det enkla exemplet som ingår i distributionen:
http://www.artima.com/suiterunner/start.html

runnning JUnit Tests med Artima SuiteRunner, hur man använder Artima SuiteRunner som JUnit runner för att köra dina befintliga JUnit testsviter:
http://www.artima.com/suiterunner/junit.html

Artima SuiteRunner hemsida:
http://www.artima.com/suiterunner/index.html

Artima SuiteRunner nedladdningssida (du måste logga in på Artima.com för att ladda ner utgåvan):
http://www.artima.com/suiterunner/download.jsp

SuiteRunner Forum:
http://www.artima.com/forums/forum.jsp?forum=61

prata tillbaka!

har du en åsikt? Läsarna har redan skrivit 26 kommentarer om den här artikeln. Varför inte lägga till din?

om författaren

Bill Venners är VD för Artima Software, Inc. och chefredaktör för Artima.com. han är författare till boken, Inside The Java Virtual Machine, en programmeringsorienterad undersökning av Java-plattformens arkitektur och interna. Hans populära kolumner i tidningen JavaWorld täckte Java internals, objektorienterad design och Jini. Bill har varit aktiv i Jini-samhället sedan starten. Han ledde Jini-samhällets ServiceUI-projekt som producerade ServiceUI API. ServiceUI blev det de facto vanliga sättet att associera användargränssnitt till Jini-tjänster och var den första jini community-standarden som godkändes via jini-beslutsprocessen. Bill fungerar också som en vald medlem av Jini Community ’ s initial Technical Oversight Committee (TOC), och i denna roll bidrog till att definiera styrningsprocessen för samhället. Han ägnar för närvarande det mesta av sin energi åt att bygga Artima.com till en allt mer användbar resurs för utvecklare.

You might also like

Lämna ett svar

Din e-postadress kommer inte publiceras.