Tilnærming 1: Ikke Test Private Metoder

Testing Private Metoder Med JUnit Og SuiteRunner
Av Bill Venners
Mai 24, 2004
Sammendrag

denne artikkelen sammenligner fire forskjellige tilnærminger til testing av private metoder i Java-klasser.

min aller første bruk Av JUnit var å bygge et konformitetstestsett for ServiceUI API . Formålet med et testsett for samsvar er å bidra til at alternative implementeringer av SAMME API er kompatible med API-spesifikasjonen. FORDI EN API-spesifikasjon bare definerer det offentlige grensesnittet TIL API-EN, ikke API-implementeringen, utøver en samsvarstest bare det offentlige grensesnittet. Med andre ord er en konformitetstest en» svart boks » – test. DEN behandler API under test som en svart boks, hvis eksternt grensesnitt kan ses, men hvis interne implementering ikke kan. En samsvarstest av En Java API trenger derfor bare tilgang til de offentlige medlemmene av pakkene og klassene under test. Det er ikke nødvendig å få tilgang til pakkenivå, beskyttet, eller private medlemmer.

da Jeg senere brukte JUnit til oppgaven med å skrive faktiske enhetstester, i motsetning til konformitetstester, fant jeg meg selv å skrive white box—tester-tester som benytter kunnskap om den interne implementeringen av pakkene og klassene under test. Mens jeg bare ønsket å teste offentlige metoder i mine konformitetstester, ønsket jeg å skrive enhetstester for pakketilgang og noen ganger private metoder samt offentlige metoder.

Daniel Steinberg viste meg Den vanlige JUnit-teknikken for å bruke parallelle kildekodetrær, som tillot meg å plassere testklasser i samme pakke som klassene under test, men holde dem i en annen katalog. Dette ga en ren separasjon av test-og produksjonskode. Ved å plassere begge kilde trær I CLASSPATH, mine test klasser kunne få tilgang pakke-nivå metoder og klasser i pakken under test. Dette forlot meg imidlertid med problemet med å teste private metoder.

Da Jeg spurte Daniel om å teste private metoder, foreslo Han forsiktig at jeg tester de private metodene indirekte ved å teste pakken-tilgang og offentlige metoder som kaller de private. Dette svaret tilfredsstilte meg ikke helt, for noen ganger følte jeg virkelig trang til å teste en privat metode direkte. Min første løsning var å bare gjøre slike private metoder pakke tilgang, som tillot meg å teste dem direkte Med JUnit fra testklasser i samme pakke i parallell kilde treet. Dette fungerte fint, men fikk meg til å føle meg litt skitten på en eller annen måte. Selv om jeg generelt oppdaget at å tenke på hvordan man designer grensesnitt, slik at de lett kunne testes, hjalp meg med å designe bedre grensesnitt, i dette tilfellet følte jeg at jeg gjorde designet litt verre for å gjøre det testbart.

da jeg senere endte opp med å delta i etableringen av Hva Frank Sommers, Matt Gerrans, og jeg til slutt utgitt Som Artima SuiteRunner, lovet jeg at jeg ville gjøre testingen av private metoder enklere I SuiteRunner enn Det er I JUnit. Men etter å ha undersøkt de ulike tilnærminger til testing private metoder, jeg bestemte meg for ikke å gjøre noe spesielt I SuiteRunner å støtte testing private metoder. Så om Du bruker JUnit eller SuiteRunner, du har de samme fire grunnleggende tilnærminger til testing private metoder:

  • ikke test private metoder.
  • Gi metodepakken tilgang.
  • Bruk en nestet testklasse.
  • Bruk refleksjon.

i denne artikkelen vil jeg diskutere disse fire tilnærmingene til testing av private metoder I Java. Jeg vil se på fordeler og ulemper ved hver og forsøke å kaste lys over når det er fornuftig å bruke hver tilnærming.

som jeg nevnte i innledningen, hørte jeg først rådet om å undertrykke mine sporadiske oppfordringer til å teste private metoder fra Daniel Steinberg. Men Daniel er ikke bare kilden til dette rådet som jeg har møtt. Det ser ut til å være en felles holdning I Java-samfunnet. FOR Eksempel sier JUNIT FAQ:

Testing av private metoder kan være en indikasjon på at disse metodene skal flyttes inn i en annen klasse for å fremme gjenbrukbarhet.

Charles Miller uttrykte et lignende synspunkt i sin blogg:

hvis du har en grundig serie med tester for en klasses eksponerte (ikke-private) grensesnitt, bør disse testene, i sin natur, verifisere at enhver privat metode i klassen også fungerer. Hvis dette ikke er tilfelle, eller hvis du har en privat metode så kompleks at den må testes ut av konteksten til sine offentlige innringere, vil jeg vurdere det som en kode-lukt.

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

generelt vil du ikke bryte noen innkapsling for testens skyld (Eller Som Mor pleide å si, «ikke utsett dine private!»). Mesteparten av tiden, bør du være i stand til å teste en klasse ved å utøve sine offentlige metoder. Hvis det er betydelig funksjonalitet som er skjult bak privat eller beskyttet tilgang, kan det være et advarselsskilt at det er en annen klasse der inne som sliter med å komme seg ut.

jeg tror alt dette rådet. Mesteparten av tiden, private metoder kan mest effektivt testet via tilnærming 1, indirekte ved å teste pakken nivå, beskyttet, og offentlige metoder som kaller dem. Men uunngåelig vil noen mennesker i noen situasjoner føle at direkte testing av en privat metode er den riktige tingen å gjøre.

i mitt tilfelle pleier jeg å lage mange private verktøymetoder. Disse bruksmetodene gjør ofte ingenting med forekomstdata, de opererer bare på de passerte parametrene og returnerer et resultat. Jeg lager slike metoder for å gjøre kallemetoden lettere å forstå. Det er en måte å håndtere kompleksiteten i gjennomføringen av klassen. Nå, hvis jeg trekker ut den private metoden ut av en metode som allerede fungerer og har god enhetstestdekning, vil de eksisterende enhetstestene trolig være tilstrekkelig. Jeg trenger ikke skrive flere enhetstester bare for den private metoden. Men hvis jeg vil skrive den private metoden før den ringer, og jeg vil skrive enhetstestene før jeg skriver den private metoden, er jeg tilbake til å teste den private metoden direkte. I tilfelle av private verktøy metoder, føler jeg ikke min trang til å direkte teste metodene er, Som JUnit FAQ si det ,» en indikasjon på at disse metodene bør flyttes inn i en annen klasse for å fremme gjenbrukbarhet.»Disse metodene er egentlig bare nødvendig i klassen der de bor, og faktisk kalles de ofte bare av en annen metode.

En annen grunn til at jeg noen ganger føler trang til å teste private metoder direkte, er at jeg pleier å tenke på enhetstesting som å hjelpe meg med å oppnå et robust system ved å bygge det systemet ut av robuste deler. Hver del er en «enhet» som jeg kan skrive » enhetstester.»Enhetstestene hjelper meg med å sikre at hver enhet fungerer riktig, noe som igjen hjelper meg med å bygge et system som fungerer riktig som en helhet. Den primære enheten jeg tenker når det gjelder programmering I Java, er klassen. Jeg bygger systemer ut av klasser, og enhetstester gir meg tillit til at klassene mine er robuste. Men til en viss grad føler jeg også på samme måte om de private metodene som jeg komponerer pakke-tilgang,beskyttet og offentlige metoder. Disse private metodene er enheter som kan testes individuelt. Slike enhetstester gir meg tillit til at de private metodene fungerer som de skal, noe som hjelper meg med å bygge pakketilgang, beskyttede og offentlige metoder som er robuste.

som jeg nevnte i introduksjonen, var methods package access min første tilnærming til å teste private metoder Med JUnit. Denne tilnærmingen fungerer faktisk helt fint, men det kommer med en liten kostnad. Når jeg ser en privat tilgangsspesifikator på en metode, forteller det meg noe jeg liker å vite-at dette er en del av implementeringen av klassen. Jeg vet at jeg kan ignorere metoden hvis jeg bare prøver å bruke klassen fra en annen klasse i pakken. Jeg kunne finne ut dette om en pakketilgangsmetode ved å se nærmere på navnet, dokumentasjonen og koden til metoden, men ordet privat kommuniserer dette langt mer effektivt. Videre er hovedproblemet jeg har med denne tilnærmingen filosofisk. Selv om jeg ikke har noe imot å «bryte innkapsling for testens skyld», som Dave og Andy ville si det, føler Jeg meg ikke bra om å bryte innkapsling på en MÅTE som endrer pakkenivå API. Med andre ord, selv om jeg er ganske entusiastisk til å teste ikke-offentlige metoder for klasser, dvs. å lage «white-box» – enhetstester, vil jeg heller AT API – en i klassene under test, inkludert pakkenivå API, ikke endres for å lette disse testene.

Tilnærming 3: Bruk En Nestet Testklasse

en tredje tilnærming til testing av private metoder er å neste en statisk testklasse inne i produksjonsklassen som testes. Gitt at en nestet klasse har tilgang til de private medlemmene av sin omsluttende klasse, ville den kunne påkalle de private metodene direkte. Den statiske klassen i seg selv kan være pakketilgang, slik at den kan lastes som en del av den hvite boksprøven.

ulempen med denne tilnærmingen er at hvis du ikke vil at den nestede testklassen skal være tilgjengelig i deployment JAR-filen, må du gjøre litt ekstra arbeid for å trekke den ut. Også, noen mennesker kan ikke like å ha testkode blandet i samme fil som produksjonskode, selv om andre kanskje foretrekker den tilnærmingen.

Tilnærming 4: Bruk Refleksjon

den fjerde tilnærmingen til testing av private metoder ble foreslått for Meg Av Vladimir R. Bossicard, som skrev JUnit Addons . En dag over lunsj opplyste Vladimir meg at java.lang.reflect API inkluderte metoder som tillot klientkode å omgå tilgangsbeskyttelsesmekanismen Til Java virtual machine. Han fortalte meg også at Hans JUnit Addons-prosjekt inkluderte en klasse, junitx.util.PrivateAccessor, for å bistå med å bruke reflection API for nettopp dette formålet: å skrive enhetstester som manipulerer private medlemmer av klassene under test. JUNIT FAQ peker på en lignende klasse, kalt PrivilegedAccessor , skrevet av Charlie Hubbard og Prashant Dhotke.

en fordel ved å bruke refleksjonstilnærmingen til testing av private metoder er at den gir en ren separasjon av testkode og produksjonskode. Testene trenger ikke være nestet inne i klassen under test, som i tilnærming 3. Snarere kan de plasseres sammen med de andre testene som utøver klassens pakkenivå og offentlige metoder. I tillegg trenger DU ikke endre API for klassen under test. I motsetning til tilnærming 2 kan private metoder forbli private. I motsetning til approach 3 trenger du ikke legge til noen ekstra nestet klasse på pakketilgangsnivå. Den største ulempen ved denne tilnærmingen er at testkoden er langt mer verbose fordi den bruker reflection API. I tillegg er refactoring-Ideer som Eclipse og IntelliJ vanligvis ikke så flinke til å endre navnene på metoder der de refereres til som Strings overført til metodene til reflection API. Så hvis du endrer navnet på den private metoden med refactoring IDE, må du kanskje gjøre noen endringer for hånd i testkoden.

Et Eksempel

For å gi et eksempel på en privat metode som etter min mening fortjener direkte enhetstesting, hentet jeg noe funksjonalitet ut av

main– metoden i klassenorg.suiterunner.Runner.Runner.mainanalyserer kommandolinjeargumenter og kjører en pakke med tester, eventuelt skyte OPP GUI. Metoden jeg hentet ut,parseArgsIntoLists, gjør en del av arbeidet med å analysere kommandolinjeargumentene Til SuiteRunner-programmet. Nå, for å teste den offentlige metoden som kaller denne private metoden, må jeg testemain. Hoved, selvfølgelig, er hele programmet, noe som gjør metoden ganske vanskelig å teste. Faktisk har jeg ingen eksisterende test formain.

på dette punktet lurer du kanskje på om jeg skrev tester først i stil med testdrevet utvikling, hvordan endte jeg med å skrive parsingskode som ikke hadde noen enhetstester? Hovedårsaken er at min testinfeksjon har kommet i etapper. Jeg fikk faktisk en enhetstestinfluensa lenge før Jeg hadde hørt Om JUnit eller les Testinfisert . Tilbake da jeg bygde Windows-applikasjoner I C++, ville jeg for eksempel skrive litt kode for å teste en nylig implementert metode, deretter utføre den koden og se den utføre ved å gå gjennom metoden under test med debuggeren. Denne typen enhetstesting hjalp meg med å oppnå robusthet, men testene selv sjekket ikke for riktig oppførsel. Jeg sjekket for riktig oppførsel selv ved å observere via debuggeren. Testene ble ikke automatisert, og derfor lagret jeg ikke dem slik at de kunne kjøres igjen senere. Da Jeg leste Testinfisert, så jeg umiddelbart verdien av å automatisere testene og holde dem rundt som en slags regresjonstest etter refactoring, men i lang tid var det ikke fornuftig for meg å skrive testene først. Jeg ønsket å skrive testene etter at jeg implementerte funksjonaliteten, fordi det var da jeg hadde kjørt testene med debuggeren. En sekundær grunn til at jeg ikke skrev tester først mens jeg utviklet Mye Av SuiteRunner, er at jeg ønsket å skrive SuiteRunner-tester med SuiteRunner selv, i et forsøk på å spise min egen hundemat. Inntil SuiteRunner ‘ s basic API avgjort, hadde jeg ikke testverktøyet jeg ønsket å bruke til å skrive testene.

siden den gang har imidlertid testviruset tatt et sterkere grep på meg, og jeg foretrekker nå å skrive enhetstester først mesteparten av tiden. Jeg foretrekker å skrive tester først, ikke så mye fordi jeg finner at jeg ender med renere design, som vanligvis fremmes som hovedfordelen ved testdrevet utvikling. Snarere foretrekker jeg å skrive tester først fordi jeg finner det ofte hvis jeg dykker inn i koden under press, med den hensikt at jeg skal skrive testen senere, blir testen faktisk aldri skrevet. SuiteRunner selv har svært få enhetstester på dette punktet av den grunn. Her er metoden parseArgsIntoLists :

 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); } } }

kommandolinjen for SuiteRunner inneholder tre typer informasjon Som Brukes Av SuiteRunner til å kjøre tester: runpath, reportere og suiter. parseArgsIntoLists – metoden går bare gjennom argumentene som sendes som en matrise på String s, og plasserer hvert argument i en av listene, runpathList, reportersList og suitesList.

Før jeg skriver en test for denne private metoden, vil jeg spørre om min trang til å skrive denne enhetstesten representerer en kode lukt, Som Charles Miller sa det i sin blogg? Betyr det at parseArgsIntoLists skal flyttes til en annen klasse for å fremme gjenbruk, som JUnit FAQ antyder? Ville Dave og Andy si at det er et advarselsskilt at det er en annen klasse der inne som sliter med å komme seg ut? Vel, kanskje. Jeg kunne utvilsomt lage en ArgumentsParser klasse som bare har noen statiske metoder som utfører analysearbeidet. Både ArgumentsParser – klassen og metodene den inneholder, kan være pakketilgang, noe som gjør dem enkle å teste. Men det føles bare ikke riktig for meg. Disse metodene kalles bare av Runner.main. De føles helt klart som private metoder for meg. Den eneste grunnen til at jeg ville flytte dem til en ArgumentsParser klasse er å kunne teste dem. Jeg ville faktisk bruke tilnærming nummer 2: gjør private metoder pakken tilgang.

I Stedet for dette eksemplet bestemte jeg meg for å ta tilnærming nummer 4, og bruke refleksjon. Jeg så På Både Vladimir Bossicards junitx.utils.PrivateAccessor Og Charlie Hubbard og Prashant Dhotke PrivilegedAccessor, men bestemte meg for at ingen av dem hjalp meg helt slik jeg ønsket. For det første har disse klassene begge muligheten til å teste felt for å sikre at de er satt riktig. Så langt har jeg aldri følt noen trang til å få direkte tilgang til private felt fra enhetstester. Jeg vil bare være i stand til å teste private verktøy metoder. Hovedproblemet jeg hadde med disse to klassene, er imidlertid hvordan de behandlet unntakene som kan kastes når de prøver å påkalle den private metoden via refleksjon. Hver klasse har en eller flere metoder hvis jobb det er å påkalle en metode med refleksjon. PrivilegedAccessor‘s to invokeMethod metoder sender ethvert unntak tilbake til sin innringer, inkludert tre merkede unntak som er deklarert i kast-klausulen: NoSuchMethodException, IllegalAccessException og InvocationTargetException. I motsetning til dette fanger PrivateAccessor‘s to invoke metoder InvocationTargetException, og trekker ut og kaster målunntaket, det faktiske unntaket kastet av den påberopte metoden. Det fanger deretter noe annet unntak, og kaster NoSuchMethodException. Jeg likte ikke at den som ringer PrivilegedAccessor.invokeMethod alltid måtte håndtere de tre kontrollerte unntakene, fordi jeg skjønte at den generelle måten å håndtere unntak ville være å la testen mislykkes. Jeg var også opptatt av at PrivateAccessor.invoke kastet bort potensielt nyttig stakksporinformasjon i sin unntakshåndteringspolicy. Det jeg virkelig ønsket var en metode som forsøkte å påkalle en privat metode med refleksjon, som pakket inn et kastet unntak i tillegg til InvocationTargetException i en ukontrollert TestFailedException. Mesteparten av tiden vil dette unntaket føre til at testen mislykkes. I tester som ventet at et unntak skulle kastes, kunne unntaket i InvocationTargetException trekkes ut og testes for korrekthet.

derfor skrev jeg invokeStaticMethod. setAccessible(true) – anropet er det som gjør at den private metoden kan påberopes fra utenfor klassen. En tilsvarende invokeStaticMethod implementering for Bruk Med JUnit ville kaste AssertionFailedError i stedet for TestFailedException. Her er 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); } }

Deretter opprettet jeg en bekvemmelighetsmetode som påkaller den spesielle private metoden jeg ønsket å teste:

 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); }

Til slutt kunne jeg skrive tester mot den private metoden uten for mye overflødig rot, slik som dette:

 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)); }

Konklusjon

Tilnærming 1, testing av private metoder indirekte ved å teste pakkenivå, beskyttede og offentlige metoder som kaller dem, vil ofte være den beste tilnærmingen. I tilfeller der du virkelig ønsker å teste private metoder direkte, bruker refleksjon for å teste private metoder, selv om det er ganske tungvint, gir den reneste separasjonen av testkode fra produksjonskode og minst innvirkning på produksjonskoden. Men hvis du ikke har noe imot å gjøre de spesielle private metodene du vil teste pakketilgang, kan du bruke tilnærming 2. Eller hvis du ikke har noe imot å plassere en nestet testklasse i produksjonsklassen din under test, vil tilnærming 3 i det minste la deg holde de private metodene private.

Det er ikke et perfekt svar. Men hvis du vedtar tilnærming 4, vil du til slutt ende opp med en håndfull metoder som invokeStaticMethod som du kan gjenbruke. Når du skriver en bekvemmelighetsmetode, som invokeParseArgsIntoLists, for en privat metode, kan du skrive tester mot den private metoden uten mye problemer.

Ressurser

1. ServiceUI API definerer en standard måte å knytte brukergrensesnitt Til jini tjenester:
http://www.artima.com/jini/serviceui/index.html

2. Daniel Steinberg Er For tiden Sjefredaktør for Java.NET:
http://www.java.net/

3. Artima SuiteRunner er en gratis åpen kildekode testing verktøykasse Og JUnit runner:
http://www.artima.com/suiterunner/index.html

4.JUnit FAQ spørsmål om testing private metoder:
http://junit.sourceforge.net/doc/faq/faq.htm#tests_10

5. Testing Private Methods (Ikke Gjør Det), Et blogginnlegg Av Charles Miller:
http://fishbowl.pastiche.org/2003/03/28/testing_private_methods_dont_do_it

6. Andy Hunt Og Dave Thomas er forfatterne Av Pragmatic Unit Testing, som er tilgjengelig på Pragmatic Store.

7. JUnit Addons er en samling av helper klasser For JUnit skapt Av Vladimar R. Bossicard:
http://sourceforge.net/projects/junit-addons

PrivateAccessor er klassen Fra JUnit Addons som tilrettelegger testing private medlemmer:
http://junit-addons.sourceforge.net/junitx/util/PrivateAccessor.html

9.PrivilegedAccessor class, som du kan bruke til å få tilgang til private medlemmer:
http://groups.yahoo.com/group/junit/files/src/PrivilegedAccessor.java

10. Testdrevet Utvikling Ved Eksempel, Av Kent Beck, beskriver test-første teknikken:
http://www.amazon.com/exec/obidos/ASIN/0321146530/

11. Test Infisert, Av Kent Beck Og Erich Gamma, introdusert JUnit til verden:
http://junit.sourceforge.net/doc/testinfected/testing.htm

Unit Testing Private Methods, et blogginnlegg om nUnit Av Ted Graham:
http://weblogs.asp.net/tgraham/archive/2003/12/31/46984.aspx

Subverting Javas Tilgangsbeskyttelse for Enhetstesting, en O ‘ Reilly OnJava.com artikkel Av Ross Burton:
http://www.onjava.com/pub/a/onjava/2003/11/12/reflection.html

Klasse RunnerSuite, hvorfra kodebitene i denne artikkelen ble tatt, vises i sin helhet her:
http://www.artima.com/suiterunner/privateExample.html

Hvorfor Vi Refactored JUnit
http://www.artima.com/suiterunner/why.html

Artima SuiteRunner Tutorial, Bygge Konformitet Og Enhet Tester Med Artima SuiteRunner:
http://www.artima.com/suiterunner/tutorial.html

Komme i Gang Med Artima SuiteRunner, Slik Kjører Du Det Enkle Eksemplet Som Er Inkludert I Distribusjonen:
http://www.artima.com/suiterunner/start.html

Runnning JUnit Tester Med Artima SuiteRunner, slik bruker Du Artima SuiteRunner som JUnit runner for å kjøre Dine eksisterende JUnit test suiter:
http://www.artima.com/suiterunner/junit.html

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

Artima SuiteRunner nedlastingsside (du må logge på Artima.com for å laste ned utgivelsen):
http://www.artima.com/suiterunner/download.jsp

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

Snakk tilbake!

Har du en mening? Leserne har allerede lagt ut 26 kommentarer om denne artikkelen. Hvorfor ikke legge til din?

om forfatteren

Bill Venners er president I Artima Software, Inc. og sjefredaktør for Artima.com Han er forfatter Av Boken, Inside The Java Virtual Machine, en programmerer-orientert undersøkelse Av Java-plattformens arkitektur og internals. Hans populære kolonner i JavaWorld magazine dekket Java internals, objektorientert design og Jini. Bill har vært aktiv i Jini Samfunnet siden starten. Han ledet Jini-Fellesskapets ServiceUI-prosjekt som produserte ServiceUI API. ServiceUI ble de facto standard måte å knytte brukergrensesnitt Til jini tjenester, og var den første jini community standard godkjent via Jini Beslutningsprosessen. Regningen fungerer også som et valgt medlem Av Jini-Fellesskapets første Tekniske Kontrollutvalg( TOC), og bidro i denne rollen til å definere styringsprosessen for samfunnet. Han bruker for tiden mesteparten av sin energi til å bygge Artima.com til en stadig mer nyttig ressurs for utviklere.

You might also like

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert.