Testovanie abstraktnej triedy s JUnit

1. Prehľad

V tomto výučbe budeme analyzovať rôzne prípady použitia a možné alternatívne riešenia pre testovanie jednotiek abstraktných tried pomocou neabstrahových metód.

Poznač si to testovanie abstraktných tried by malo takmer vždy prechádzať cez verejné API konkrétnych implementácií, takže nasledujúce techniky nepoužívajte, pokiaľ si nie ste istí, čo robíte.

2. Maven závislosti

Začnime so závislosťami Maven:

 org.junit.jupiter junit-jupiter-engine 5.1.0 test org.mockito mockito-core 2.8.9 test org.powermock powermock-module-junit4 1.7.4 test junit junit org.powermock powermock-api-mockito2 1.7.4 test 

Najnovšie verzie týchto knižníc nájdete na serveri Maven Central.

Aplikácia Powermock nie je pre Junit5 plne podporovaná. Tiež powermock-module-junit4 sa používa iba pre jeden príklad uvedený v časti 5.

3. Nezávislá neabstraktná metóda

Uvažujme o prípade, keď máme abstraktnú triedu s verejnou neabstraktnou metódou:

public abstract class AbstractIndependent {public abstract int abstractFunc (); public String defaultImpl () {return "DEFAULT-1"; }}

Chceme metódu otestovať defaultImpl (), a máme dve možné riešenia - použiť konkrétnu triedu alebo použiť Mockito.

3.1. Používanie betónovej triedy

Vytvorte konkrétnu triedu, ktorá sa rozširuje Abstraktne nezávislý triedy a použite ju na otestovanie metódy:

public class ConcreteImpl extends AbstractIndependent {@Override public int abstractFunc () {return 4; }}
@Test public void givenNonAbstractMethod_whenConcreteImpl_testCorrectBehaviour () {ConcreteImpl conClass = new ConcreteImpl (); Reťazec skutočný = conClass.defaultImpl (); assertEquals ("DEFAULT-1", skutočné); }

Nevýhodou tohto riešenia je potreba vytvoriť konkrétnu triedu s fiktívnymi implementáciami všetkých abstraktných metód.

3.2. Pomocou Mockita

Prípadne môžeme použiť Mockito na vytvorenie falošného:

@Test public void givenNonAbstractMethod_whenMockitoMock_testCorrectBehaviour () {AbstractIndependent absCls = Mockito.mock (AbstractIndependent.class, Mockito.CALLS_REAL_METHODS); assertEquals ("DEFAULT-1", absCls.defaultImpl ()); }

Najdôležitejšou časťou je tu príprava simulácie na použitie skutočného kódu pri vyvolaní metódy použitím Mockito.CALLS_REAL_METHODS.

4. Abstraktná metóda volaná z inej ako abstraktnej metódy

V tomto prípade neabstraktná metóda definuje tok globálneho vykonania, zatiaľ čo abstraktnú metódu je možné zapísať rôznymi spôsobmi v závislosti od prípadu použitia:

verejná abstraktná trieda AbstractMethodCalling {verejný abstrakt String abstractFunc (); public String defaultImpl () {String res = abstractFunc (); návrat (res == null)? „Predvolené“: (res + „Predvolené“); }}

Na otestovanie tohto kódu môžeme použiť rovnaké dva prístupy ako predtým - buď vytvoríme konkrétnu triedu, alebo na vytvorenie falošného nástroja použijeme Mockito:

@Test public void givenDefaultImpl_whenMockAbstractFunc_thenExpectedBehaviour () {AbstractMethodCalling cls = Mockito.mock (AbstractMethodCalling.class); Mockito.when (cls.abstractFunc ()) .thenReturn ("abstrakt"); Mockito.doCallRealMethod () .when (cls) .defaultImpl (); assertEquals ("Abstraktné predvolené", cls.defaultImpl ()); }

Tu je abstractFunc () je zarovnaná s návratnou hodnotou, ktorú uprednostňujeme pre test. To znamená, že keď voláme neabstraktnú metódu defaultImpl (), použije tento pahýľ.

5. Neabstrahujúca metóda s obštrukciou testu

V niektorých scenároch volá metóda, ktorú chceme testovať, súkromnú metódu, ktorá obsahuje prekážku testu.

Pred testovaním cieľovej metódy musíme obísť prekážkovú testovaciu metódu:

verejná abstraktná trieda AbstractPrivateMethods {public abstract int abstractFunc (); public String defaultImpl () {return getCurrentDateTime () + "DEFAULT-1"; } private String getCurrentDateTime () {return LocalDateTime.now (). toString (); }}

V tomto príklade defaultImpl () metóda volá súkromnú metódu getCurrentDateTime (). Táto súkromná metóda získava aktuálny čas za behu, čomu by sa malo v našich testoch jednotiek vyhnúť.

Teraz, aby sme sa vysmievali štandardnému chovaniu tejto súkromnej metódy, nemôžeme ani použiť Mockito pretože nemôže ovládať súkromné ​​metódy.

Namiesto toho musíme použiť PowerMock (nUpozorňujeme, že tento príklad funguje iba s JUnit 4, pretože podpora tejto závislosti nie je k dispozícii pre JUnit 5):

@RunWith (PowerMockRunner.class) @PrepareForTest (AbstractPrivateMethods.class) verejná trieda AbstractPrivateMethodsUnitTest {@Test verejná neplatnosť whenMockPrivateMethod_thenVerifyBehaviour () {AbstractPrivateMethods mockClass = AbstractMobitoMetito PowerMockito.doCallRealMethod () .when (mockClass) .defaultImpl (); Reťazec dateTime = LocalDateTime.now (). ToString (); PowerMockito.doReturn (dateTime) .when (mockClass, "getCurrentDateTime"); Reťazec skutočný = mockClass.defaultImpl (); assertEquals (dateTime + "DEFAULT-1", skutočný); }}

Dôležité bity v tomto príklade:

  • @RunWith definuje PowerMock ako bežca pre test
  • @PrepareForTest (trieda) hovorí PowerMocku, aby pripravil triedu na neskoršie spracovanie

Je zaujímavé, že sa pýtame PowerMock zavrhnúť súkromnú metódu getCurrentDateTime (). PowerMock ho použije pomocou odrazu, pretože nie je prístupný zvonka.

Takže, keď voláme defaultImpl (), stub vytvorený pre súkromnú metódu bude vyvolaný namiesto skutočnej metódy.

6. Neabstrahujúca metóda, ktorá pristupuje k poliam inštancií

Abstraktné triedy môžu mať vnútorný stav implementovaný s poľami tried. Hodnota polí môže mať významný vplyv na testovanú metódu.

Ak je pole verejné alebo chránené, môžeme k nemu ľahko získať pomocou testovacej metódy.

Ak je to však súkromné, musíme použiť PowerMockito:

verejná abstraktná trieda AbstractInstanceFields {protected int count; private boolean active = false; public abstract int abstractFunc (); public String testFunc () {if (count> 5) {return "Overflow"; } návrat aktívny? "Added": "Blocked"; }}

Tu je testFunc () metóda používa polia na úrovni inštancie počítať a aktívny než sa vráti.

Pri testovaní testFunc (), môžeme zmeniť hodnotu počítať pole prístupom k inštancii vytvorenej pomocou Mockito.

Na druhej strane testovať správanie u súkromných aktívny pole, budeme musieť opäť použiť PowerMockito, a jeho Whitebox trieda:

@Test public void whenPowerMockitoAndActiveFieldTrue_thenCorrectBehaviour () {AbstractInstanceFields instClass = PowerMockito.mock (AbstractInstanceFields.class); PowerMockito.doCallRealMethod () .when (instClass) .testFunc (); Whitebox.setInternalState (instClass, "aktívny", pravda); assertEquals ("Pridané", instClass.testFunc ()); }

Vytvárame stub triedu pomocou PowerMockito.mock ()a používame Whitebox triedy na kontrolu vnútorného stavu objektu.

Hodnota aktívny pole sa zmenilo na pravda.

7. Záver

V tomto tutoriáli sme videli niekoľko príkladov, ktoré pokrývajú veľa prípadov použitia. V závislosti od použitého vzoru môžeme abstraktné triedy použiť v mnohých ďalších scenároch.

Písanie jednotkových testov pre metódy abstraktných tried je rovnako dôležité ako pre bežné triedy a metódy. Každý z nich môžeme otestovať pomocou rôznych techník alebo rôznych dostupných knižníc podpory testov.

Celý zdrojový kód je k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found