Tento článek srovnává čtyři různé přístupy k testování soukromých metod v jazyce Java tříd.
mým prvním použitím JUnit bylo vytvořit testovací sadu shody pro API ServiceUI . Účelem testovací sady shody je pomoci zajistit, aby alternativní implementace stejného API byly kompatibilní se specifikací API. Protože specifikace API definuje pouze veřejné rozhraní API, nikoli implementaci API, test shody vykonává pouze veřejné rozhraní. Jinými slovy, test shody je test“ černé skříňky“. S testovaným API zachází jako s černou skříňkou, jejíž externí rozhraní lze vidět,ale jejíž vnitřní implementace nemůže. Test shody Java API proto potřebuje přístup pouze k veřejným členům testovaných balíčků a tříd. Není třeba přistupovat k úrovni balíčku, chráněný, nebo soukromí členové.
Když jsem později použita JUnit, aby se úkol psaní skutečné jednotkové testy, oproti shody testy, jsem se ocitl, kteří chtějí psát white box testy—testy, které využívají znalosti vnitřní implementace balíčků a tříd v rámci testu. Zatímco ve svých testech shody jsem chtěl testovat pouze veřejné metody, chtěl jsem psát jednotkové testy pro přístup k balíčkům a příležitostně soukromé metody i veřejné metody.
Daniel Steinberg mi ukázal, společné JUnit techniku pomocí paralelní zdrojový kód stromy, což mi umožnilo místo zkoušky tříd ve stejném balíčku jako třídy podle testu, ale udržet je v jiném adresáři. To poskytlo čisté oddělení zkušebního a výrobního kódu. Umístěním obou zdrojových stromů do třídy CLASSPATH mohly mé testovací třídy přistupovat k metodám a třídám na úrovni balíčku v testovaném balíčku. To mi však stále zůstalo s problémem testování soukromých metod.
když jsem se zeptal Daniela na testování soukromých metod, jemně navrhl, abych testoval soukromé metody nepřímo testováním přístupových a veřejných metod, které nazývají soukromé. Tato odpověď mě zcela neuspokojila, protože občas jsem opravdu cítil nutkání přímo otestovat soukromou metodu. Mým počátečním řešením bylo pouze vytvořit přístup k takovým soukromým metodám, což mi umožnilo otestovat je přímo s JUnit z testovacích tříd ve stejném balíčku v paralelním zdrojovém stromu. Fungovalo to dobře, ale nějak jsem se cítil trochu špinavý. I když jsem obecně zjistil, že přemýšlení o tom, jak navrhnout rozhraní, aby mohla být snadno testována jednotkou, mi pomohlo navrhnout lepší rozhraní, v tomto případě jsem cítil, že design dělám o něco horší, aby byl testovatelný.
Když jsem později skončil podílí na vytváření toho, co Frank Sommers, Matt Gerrans, a nakonec jsem se vydala jako Artima SuiteRunner , slíbil jsem, že už by se testování soukromých metod jednodušší v SuiteRunner, než je v JUnit. Ale po zkoumání různých přístupů k testování soukromých metod, rozhodl jsem se udělat něco zvláštního v SuiteRunner na podporu testování soukromých metod. Takže ať už jste pomocí JUnit nebo SuiteRunner, máte stejné čtyři základní přístupy k testování soukromých metod:
- nechci testovat privátní metody.
- dát přístup metody balíček.
- použijte vnořenou testovací třídu.
- použijte odraz.
v tomto článku se budu zabývat těmito čtyřmi přístupy k testování soukromých metod v Javě. Podívám se na výhody a nevýhody každého z nich a pokusím se osvětlit, kdy má smysl používat každý přístup.
jak jsem zmínil v úvodu, poprvé jsem slyšel radu, jak potlačit své občasné nutkání testovat soukromé metody od Daniela Steinberga. Ale Daniel není jen zdrojem této rady, se kterou jsem se setkal. Zdá se, že je to běžný postoj v komunitě Java. Například JUnit ČKD státy:
Testování soukromých metod může být známkou toho, že tyto metody by měly být přesunuty do jiné třídy, aby podporovaly opětovné použití.
Charles Miller vyjádřil podobný pohled na jeho weblog :
Pokud budete mít důkladné sadu testů pro třídu je vystaven (non-soukromé) rozhraní, tyto testy by měly, podle své povahy, ověřte, že žádné soukromé metoda v rámci třídy také funguje. Pokud tomu tak není, nebo pokud máte soukromou metodu tak složitou, že je třeba ji testovat mimo kontext jejích veřejných volajících, považoval bych to za vůni kódu.
a Dave Thomas a Andy Hunt ve své knize Pragmatic Unit Testing píší:
obecně nechcete přerušit žádné zapouzdření kvůli testování (nebo jak maminka říkala: „nevystavujte své přirození!“). Většinu času byste měli být schopni otestovat třídu cvičením jejích veřejných metod. Pokud existuje významná funkce, která se skrývá za soukromým nebo chráněným přístupem, může to být varovný signál, že tam je další třída, která se snaží dostat ven.
věřím všem těmto radám. Většinu času, soukromé metody mohou být nejefektivněji testovány pomocí přístupu 1, nepřímo testováním úrovně balíčku, chráněné, a veřejné metody, které je nazývají. Ale nevyhnutelně, někteří lidé v některých situacích budou mít pocit, že přímé testování soukromé metody je správná věc.
v mém případě mám tendenci vytvářet mnoho metod soukromého nástroje. Tyto metody nástroje často nedělají nic s daty instance, pracují pouze na předaných parametrech a vracejí výsledek. Vytvářím takové metody, aby byla metoda volání srozumitelnější. Je to způsob, jak řídit složitost implementace třídy. Nyní, pokud extrahuji soukromou metodu z metody, která již funguje a má dobré pokrytí testem jednotek, pak tyto stávající testy jednotek pravděpodobně postačí. Nemusím psát více jednotkových testů jen pro soukromou metodu. Ale pokud chci napsat vlastní metodu, než jeho volání metody, a chci psát unit testy, než psát soukromou metodu, jsem zase chtěl přímo testovat privátní metody. V případě soukromých utility metod, nemám pocit, moje touha přímo zkušební metody je, jako JUnit ČKD, „údaj, že tyto metody by měly být přesunuty do jiné třídy, aby podporovaly opětovné použití.“Tyto metody jsou skutečně potřebné pouze ve třídě, ve které sídlí, a ve skutečnosti jsou často nazývány pouze jednou jinou metodou.
dalším důvodem, proč někdy cítím nutkání testovat soukromé metody přímo, je to, že mám tendenci myslet na testování jednotek jako na to, že mi pomáhá dosáhnout robustního systému vytvořením tohoto systému z robustních částí. Každá část je „jednotka“, pro kterou mohu psát “ testy jednotek.“Testy jednotek mi pomáhají zajistit, aby každá jednotka fungovala správně, což mi zase pomáhá vybudovat systém, který funguje správně jako celek. Primární jednotkou, kterou si myslím, pokud jde o programování v Javě, je třída. Stavím systémy z tříd, a jednotkové testy mi dávají jistotu, že moje třídy jsou robustní. Ale do jisté míry se také cítím stejně o soukromých metodách, z nichž skládám přístupové, chráněné a veřejné metody. Tyto soukromé metody jsou jednotky, které lze testovat jednotlivě. Takové jednotkové testy mi dávají jistotu, že soukromé metody fungují správně, což mi pomáhá budovat robustní přístupové, chráněné a veřejné metody.
jak jsem již zmínil v úvodu, giving methods package access byl můj první přístup k testování soukromých metod s JUnit. Tento přístup ve skutečnosti funguje dobře, ale přichází s mírnými náklady. Když vidím specifikátor soukromého přístupu na metodě, říká mi to něco, co bych rád věděl-že je to součást implementace třídy. Vím, že mohu tuto metodu ignorovat, pokud se jen snažím použít třídu z jiné třídy v balíčku. Jsem na to mohli přijít o balíček-přístup metoda, při bližším pohledu na název, dokumentace a kódu metody, ale slovo soukromé komunikuje daleko efektivněji. Navíc hlavní problém, který mám s tímto přístupem, je filozofický. I když mi nevadí „porušení zapouzdření pro účely testování,“ jako Dave a Andy by to dal, já jen nemám dobrý pocit o porušení zapouzdření tak, že změní balení-level API. Jinými slovy, i když jsem docela nadšený vyzkoušet non-veřejné metody tříd, tj. vytvořit „white-box“ unit testy, raději API tříd podle testu, včetně obalu-level API, nesmí být změněn s cílem usnadnit ty, testy.
přístup 3: Použijte vnořenou testovací třídu
třetím přístupem k testování soukromých metod je vnoření statické zkušební třídy do testované výrobní třídy. Vzhledem k tomu, že vnořená třída má přístup k soukromým členům své uzavřené třídy, bude moci vyvolat soukromé metody přímo. Samotná statická třída by mohla být přístup k balíčkům, což by umožnilo její načtení v rámci testu white box.
nevýhodou tohoto přístupu je, že pokud nechcete, aby se vnořené test třídy jsou přístupné ve vašem nasazení souboru JAR, budete muset udělat trochu práce navíc, aby extrahovat. Někteří lidé také nemusí mít rádi testovací kód smíchaný ve stejném souboru jako produkční kód, i když jiní mohou tento přístup upřednostňovat.
Přístup 4: Použití Reflexe
čtvrtý přístup k testování soukromých metod bylo navrženo, aby mi Vladimir R. Bossicard, který napsal JUnit Addony . Jednoho dne během oběda, Vladimír osvícený mi, že java.lang.reflect
API zahrnuty metody, které umožnily kód klienta obejít ochranu přístupu mechanismus Java virtual machine. Také mi řekl, že jeho JUnit Addony projekt zahrnoval třídy, junitx.util.PrivateAccessor
při použití reflection API jen pro tento účel: chcete-li psát unit testy, které manipulují soukromé členy třídy v testu. JUnit FAQ poukazuje na podobnou třídu nazvanou PrivilegedAccessor
, kterou napsali Charlie Hubbard a Prashant Dhotke.
Jednou z výhod použití reflexe přístupu k testování soukromých metod je, že poskytuje čisté oddělení kód, testovací a výrobní kód. Testy nemusí být vnořeny uvnitř testované třídy, jako v přístupu 3. Spíše mohou být umístěny vedle dalších testů, které provádějí metody na úrovni balíčku a veřejné třídy. Kromě toho nemusíte měnit API testované třídy. Na rozdíl od přístupu 2 mohou soukromé metody zůstat soukromé. Na rozdíl od přístupu 3 nemusíte přidávat žádné další vnořené třídy na úrovni přístupu k balíčkům. Hlavní nevýhodou tohoto přístupu je, že testovací kód je mnohem podrobnější, protože používá reflection API. Kromě toho refaktoring IDE, jako je Eclipse a IntelliJ, obvykle nejsou tak zběhlí ve změně názvů metod, kde jsou označovány jako String
s předané metodám reflection API. Pokud tedy změníte název soukromé metody pomocí refaktoringu IDE, možná budete muset provést některé změny ručně v testovacím kódu.
příklad
abych uvedl jeden příklad soukromé metody, která si podle mého názoru zaslouží přímé testování jednotek, extrahoval jsem některé funkce z metodymain
třídyorg.suiterunner.Runner
.Runner.main
analyzuje argumenty příkazového řádku a spustí sadu testů, případně vypálí GUI. Metoda, kterou jsem extrahoval,parseArgsIntoLists
, dělá část práce parsování argumentů příkazového řádku do aplikace SuiteRunner. Nyní, abych otestoval veřejnou metodu, která volá tuto soukromou metodu, musel bych otestovatmain
. Hlavní je samozřejmě celá aplikace,díky níž je metoda poměrně obtížná. Ve skutečnosti nemám žádný existující test promain
.
V tomto bodě, můžete se zeptat, když jsem psala první testy ve stylu test-řízený vývoj , jak jsem skončil psaní parsování kódu, který neměl žádné unit testy? Hlavním důvodem je, že moje testovací infekce přišla ve fázích. Vlastně jsem chytil jednotkovou testovací chřipku dlouho předtím, než jsem slyšel o JUnit nebo číst Test infikovaný . Když jsem byl budování aplikací pro Windows v C++, například, měl bych napsat kousek kódu k testování nově implementovaná metoda, pak spustit tento kód a sledovat jej spustit pomocí krokování metoda podle testu s ladicí program. Tento druh testování jednotek mi pomohl dosáhnout robustnosti, ale samotné testy nekontrolovaly správné chování. Sám jsem zkontroloval správné chování pozorováním pomocí debuggeru. Testy nebyly automatizované, a proto jsem je neuložil, aby mohly být později znovu spuštěny. Když jsem četl Test Infected, okamžitě jsem viděl hodnotu automatizace testů a jejich udržování jako druh regresního testu po refaktorování, ale dlouho mi nedávalo smysl psát testy jako první. Chtěl jsem psát testy poté, co jsem implementoval funkčnost, protože to bylo, když jsem spustil testy s debuggerem. Sekundární důvod, proč jsem nechtěl psát testy při vývoji moc SuiteRunner je, že jsem chtěl napsat SuiteRunner testy s SuiteRunner sám, ve snaze jíst své vlastní psí žrádlo. Dokud SuiteRunner základní API usadil, jsem neměl na testování toolkit jsem chtěl napsat testy.
od té doby mě však testovací virus zaujal silněji a nyní raději píšu testy jednotek nejprve většinu času. Raději píšu testy nejprve ne tolik, protože jsem zjistil, že skončím s čistšími návrhy, což je obvykle propagováno jako hlavní výhoda vývoje řízeného testem. Spíše, raději psát testy první, protože jsem zjistil, že často, když jsem se ponořit do kódu pod tlakem, s úmyslem, že budu psát test později, test není ve skutečnosti vůbec zapsány. SuiteRunner sám má velmi málo jednotkových testů v tomto bodě právě z tohoto důvodu. Zde je metoda 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); } } }
příkazový řádek pro SuiteRunner obsahuje tři typy informací, které SuiteRunner používá ke spuštění testů: runpath, reportéři, a apartmá. parseArgsIntoLists
metoda pouze prochází argumenty předány jako pole String
s, a místa, každý argument do jednoho ze seznamů, runpathList
, reportersList
, a suitesList
.
než napíšu test pro tuto soukromou metodu, zeptal bych se, zda moje nutkání napsat tento test jednotky představuje vůni kódu, jak to uvedl Charles Miller ve svém weblogu? Znamená to, že parseArgsIntoLists
by měl být přesunut do jiné třídy, aby se podpořila opětovná použitelnost,jak naznačuje FAQ JUnit? Dave a Andy by řekli, že je to varovný signál, že tam je další třída, která se snaží dostat ven? No, možná. Mohl bych vytvořit třídu ArgumentsParser
, která obsahuje pouze několik statických metod, které provádějí analýzu. Jak třída ArgumentsParser
, tak metody, které obsahuje, mohou být přístup k balíčkům, což by je usnadnilo testování. Ale to mi prostě nepřijde správné. Tyto metody jsou volány pouze Runner.main
. Zjevně mi připadají jako soukromé metody. Jediným důvodem, proč bych je přesunul do třídy ArgumentsParser
, je být schopen je otestovat. Ve skutečnosti bych používal přístup číslo 2: zpřístupněte balíček soukromých metod.
místo toho jsem se pro tento příklad rozhodl vzít přístup číslo 4 a použít reflexi. Podíval jsem se na junitx.utils.PrivateAccessor
Vladimíra Bossicarda a PrivilegedAccessor
Charlieho Hubbarda a Prashanta Dhotkeho, ale rozhodl jsem se, že ani jeden z nich mi nepomohl tak, jak jsem chtěl. Pro jednu věc, tyto třídy mají schopnost testovat pole, aby se ujistil, že jsou správně nastaveny. Dosud jsem nikdy necítil nutkání přímo přistupovat k soukromým polím z jednotkových testů. Jen chci být schopen testovat soukromé užitkové metody. Hlavní problém, který jsem měl s těmito dvěma třídami, je však to, jak se vypořádali s výjimkami, které mohou být vyvolány při pokusu o vyvolání soukromé metody prostřednictvím reflexe. Každá třída má jednu nebo více metod, jejichž úkolem je vyvolat metodu s odrazem. PrivilegedAccessor
dvě invokeMethod
metody prochází všechny výjimky zpět do jeho volajícího, včetně tří zkontrolovat výjimky deklarované v hody článek: NoSuchMethodException
, IllegalAccessException
, a InvocationTargetException
. Naopak, PrivateAccessor
dvě invoke
metody chytit InvocationTargetException
a extrakt a hodit na cíl výjimkou, aktuální výjimka je vyvolána vyvolaný metoda. Pak chytí jakoukoli jinou výjimku a hodí NoSuchMethodException
. Nelíbilo se mi, že volající PrivilegedAccessor.invokeMethod
vždy je třeba zvládnout tři kontrolovaných výjimek, protože jsem myslel, že obecný způsob, jak zvládnout jakoukoliv výjimkou by bylo, aby test nezdaří. Byl jsem také znepokojen tím, že PrivateAccessor.invoke
vyhazoval potenciálně užitečné informace o trasování zásobníku ve svých zásadách zpracování výjimek. To, co jsem opravdu chtěl, bylo způsob, který se pokusil vyvolat privátní metoda s odrazem, což zabalené nějaké vyvolána výjimka, kromě InvocationTargetException
v nekontrolované TestFailedException
. Většinou by tato výjimka způsobila selhání testu. V testech, které očekávaly, že bude vyvolána výjimka, mohla být výjimka obsažená v InvocationTargetException
extrahována a testována na správnost.
proto jsem napsal invokeStaticMethod
. Volání setAccessible(true)
je to, co umožňuje vyvolání soukromé metody mimo třídu. Odpovídající invokeStaticMethod
implementace pro použití s JUnit by hodil AssertionFailedError
spíše než TestFailedException
. Tady je kód:
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ále jsem vytvořil pohodlí metodu, která vyvolá konkrétní soukromou metodu jsem chtěl vyzkoušet:
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); }
konečně jsem mohla psát testy proti soukromou metodu, aniž by příliš mnoho přebytečný nepořádek, jako je tento:
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)); }
Závěr
Přístup 1, testování soukromých metod nepřímo testováním balíčku úrovni, chráněné a veřejné metody, které jim říkají, je často nejlepší přístup. V případech, kdy opravdu chcete testovat privátní metody přímo pomocí reflexe testovat privátní metody, i když poněkud těžkopádné, poskytuje nejčistší oddělení kontrolní kód z výroby kód, a nejmenší vliv na produkci kódu. Pokud vám však nevadí provést tyto konkrétní soukromé metody, které chcete otestovat přístup k balíčkům, můžete použít přístup 2. Nebo pokud vám nevadí umístit vnořenou testovací třídu do vaší výrobní třídy pod test, přístup 3 by vám alespoň umožnil ponechat soukromé metody soukromé.
neexistuje dokonalá odpověď. Ale pokud přijmete přístup 4, nakonec skončíte s hrstkou metod, jako je invokeStaticMethod
, které můžete znovu použít. Jakmile napíšete pohodlnou metodu, například invokeParseArgsIntoLists
, pro soukromou metodu, můžete psát testy proti soukromé metodě bez větších obtíží.
zdroje
1. API ServiceUI definuje standardní způsob připojení uživatelských rozhraní ke službám Jini:
http://www.artima.com/jini/serviceui/index.html
2. Daniel Steinberg je v současné době šéfredaktorem Java.NET:
http://www.java.net/
3. Artima SuiteRunner je bezplatná open source testovací sada nástrojů a JUnit runner:
http://www.artima.com/suiterunner/index.html
4.JUnit FAQ Otázka o testování soukromých metod:
http://junit.sourceforge.net/doc/faq/faq.htm#tests_10
5. Testování soukromých metod (nedělej to), weblogový příspěvek Charlese Millera:
http://fishbowl.pastiche.org/2003/03/28/testing_private_methods_dont_do_it
6. Andy Hunt a Dave Thomas jsou autory Pragmatic Unit Testing, který je k dispozici v obchodě Pragmatic Store.
7. JUnit Addony je sbírka pomocné třídy pro JUnit vytvořené Vladimar R. Bossicard:
http://sourceforge.net/projects/junit-addons
PrivateAccessor
je třída z JUnit Addony, které facilates testování soukromých členů:
http://junit-addons.sourceforge.net/junitx/util/PrivateAccessor.html
9.PrivilegedAccessor class, které můžete použít pro přístup k soukromým členům:
http://groups.yahoo.com/group/junit/files/src/PrivilegedAccessor.java
10. Test řízený vývoj příkladem, Kent Beck, popisuje techniku test-first:
http://www.amazon.com/exec/obidos/ASIN/0321146530/
11. Test Infikován, Kent Beck a Erich Gamma, představil JUnit do světa:
http://junit.sourceforge.net/doc/testinfected/testing.htm
Unit Testování Soukromých Metod, blog post o nUnit Ted Graham:
http://weblogs.asp.net/tgraham/archive/2003/12/31/46984.aspx
Podrývání Java Access Protection pro Unit Testování, O ‚ reilly OnJava.com článek Ross Burton:
http://www.onjava.com/pub/a/onjava/2003/11/12/reflection.html
Class RunnerSuite
, z nichž fragmenty kódu v tomto článku byly pořízeny, se objeví v plném rozsahu zde:
http://www.artima.com/suiterunner/privateExample.html
Proč Jsme Refactored JUnit
http://www.artima.com/suiterunner/why.html
Artima SuiteRunner Tutorial, Budování Shody a Unit Testy s Artima SuiteRunner:
http://www.artima.com/suiterunner/tutorial.html
začínáme s Artima SuiteRunner, Jak Spustit Jednoduchý Příklad Zahrnuty v Distribuci:
http://www.artima.com/suiterunner/start.html
Spuštěna JUnit Testy s Artima SuiteRunner, jak používat Artima SuiteRunner jako JUnit runner spustit vaše stávající JUnit test suites:
http://www.artima.com/suiterunner/junit.html
Artima SuiteRunner domovskou stránku:
http://www.artima.com/suiterunner/index.html
Artima SuiteRunner ke stažení page (musíš přihlásit na Artima.com ke stažení vydání):
http://www.artima.com/suiterunner/download.jsp
Na SuiteRunner Fórum:
http://www.artima.com/forums/forum.jsp?forum=61
Mluvit zpět!
máte názor? Čtenáři již zveřejnili 26 komentářů k tomuto článku. Proč nepřidat své?
o autorovi
Bill Venners je prezidentem společnosti Artima Software, Inc. a šéfredaktor Artima.com. je autorem knihy Inside the Java Virtual Machine, programátorsky orientovaného průzkumu architektury a vnitřností platformy Java. Jeho populární sloupky v časopise JavaWorld pokrývaly Java internal, objektově orientovaný design a Jini. Bill je aktivní v komunitě Jini od svého vzniku. Vedl projekt služby komunity Jini, který produkoval rozhraní API ServiceUI. Na ServiceUI se stal de facto standardním způsobem spojit uživatelské rozhraní, aby Jini služby, a byl první Jini norma společenství schválena prostřednictvím Jini Rozhodovací Proces. Bill také slouží jako zvolený člen počátečního Výboru pro technický dohled komunity Jini (TOC) a v této roli pomohl definovat proces správy pro komunitu. V současné době věnuje většinu své energie budování Artima.com do stále užitečnějšího zdroje pro vývojáře.