Absztrakt osztály tesztelése JUnit segítségével

1. Áttekintés

Ebben az oktatóanyagban különféle felhasználási eseteket és az absztrakt osztályok egységvizsgálatának nem elvont módszerekkel történő lehetséges alternatív megoldásait fogjuk elemezni.

Vegye figyelembe, hogy az absztrakt osztályok tesztelésének szinte mindig át kell mennie a konkrét megvalósítások nyilvános API-ján, ezért ne alkalmazza az alábbi technikákat, hacsak nem biztos abban, hogy mit csinál.

2. Maven-függőségek

Kezdjük a Maven-függőségekkel:

 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 teszt junit junit org.powermock powermock-api-mockito2 1.7.4 teszt 

A könyvtárak legújabb verzióit a Maven Central oldalon találja meg.

A Powermock nincs teljesen támogatva a Junit5 alatt. Is, powermock-module-junit4 csak az 5. szakaszban bemutatott példa esetén használatos.

3. Független, nem absztrakt módszer

Vizsgáljuk meg azt az esetet, amikor van egy absztrakt osztályunk egy nyilvános, nem absztrakt módszerrel:

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

Szeretnénk kipróbálni a módszert defaultImpl (), és két lehetséges megoldásunk van - egy konkrét osztály vagy a Mockito használata.

3.1. Betonosztály használata

Hozzon létre egy konkrét osztályt, amely kiterjed AbsztraktFüggetlen osztály, és használja a módszer tesztelésére:

a ConcreteImpl nyilvános osztály kiterjeszti az AbstractIndependent {@Orride public int abstractFunc () {return 4; }}
@Test public void givenNonAbstractMethod_whenConcreteImpl_testCorrectBehaviour () {ConcreteImpl conClass = new ConcreteImpl (); Karaktersorozat = conClass.defaultImpl (); assertEquals ("DEFAULT-1", tényleges); }

Ennek a megoldásnak az a hátránya, hogy meg kell teremteni a konkrét osztályt az összes absztrakt módszer dummy megvalósításával.

3.2. A Mockito használata

Alternatív megoldásként használhatjuk Mockito gúny létrehozásához:

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

A legfontosabb rész itt a az ál előkészítése a valós kód használatára, amikor egy metódust meghívnak felhasználásával Mockito.CALLS_REAL_METHODS.

4. A nem absztrakt módszerből hívott absztrakt módszer

Ebben az esetben a nem absztrakt módszer meghatározza a globális végrehajtási folyamatot, míg az absztrakt módszer a felhasználási eset függvényében különböző módon írható:

public abstract class AbstractMethodCalling {public abstract String abstractFunc (); public String defaultImpl () {String res = abstractFunc (); return (res == null)? "Alapértelmezett": (res + "Alapértelmezett"); }}

A kód teszteléséhez ugyanazt a két megközelítést alkalmazhatjuk, mint korábban - vagy hozzon létre egy konkrét osztályt, vagy a Mockito segítségével hozzon létre egy gúnyt:

@Test public void givenDefaultImpl_whenMockAbstractFunc_thenExpectedBehaviour () {AbstractMethodCalling cls = Mockito.mock (AbstractMethodCalling.class); Mockito.when (cls.abstractFunc ()) .theReturn ("Abstract"); Mockito.doCallRealMethod () .when (cls) .defaultImpl (); assertEquals ("Abstract Default", cls.defaultImpl ()); }

Itt a abstractFunc () a teszthez előnyben részesített visszatérési értékkel van megakasztva. Ez azt jelenti, hogy amikor nem elvont módszert hívunk defaultImpl (), ezt a csonkot fogja használni.

5. Nem absztrakt módszer tesztelzáródással

Bizonyos esetekben a tesztelni kívánt módszer privát metódust hív, amely tesztelzáródást tartalmaz.

A cél módszer tesztelése előtt meg kell kerülnünk az akadályozó vizsgálati módszert:

public abstract class AbstractPrivateMethods {public abstract int abstractFunc (); public String defaultImpl () {return getCurrentDateTime () + "DEFAULT-1"; } privát karakterlánc getCurrentDateTime () {return LocalDateTime.now (). toString (); }}

Ebben a példában a defaultImpl () metódus hívja a privát metódust getCurrentDateTime (). Ez a privát módszer megkapja az aktuális időt futás közben, amelyet kerülni kell egységtesztjeink során.

E privát módszer szokásos viselkedésének kigúnyolására nem is használhatjuk Mockito mert nem tudja ellenőrizni a magán módszereket.

Ehelyett a PowerMock (nMegjegyzendő, hogy ez a példa csak a 4-es JUnit készülékkel működik, mivel az 5-ös JUnit-nél nem áll rendelkezésre ennek a függőségnek a támogatása):

@RunWith (PowerMockRunner.class) @PrepareForTest (AbstractPrivateMethods.class) public class AbstractPrivateMethodsUnitTest {@Test public void whenMockPrivateMethod_thenVerifyBehaviour () {AbstractPrivateMethods mockClass = PowerMockito.mock (PowerMockito.mock (PowerMockito.mock) PowerMockito.doCallRealMethod () .when (mockClass) .defaultImpl (); String dateTime = LocalDateTime.now (). ToString (); PowerMockito.doReturn (dateTime) .when (mockClass, "getCurrentDateTime"); Karaktersorozat = mockClass.defaultImpl (); assertEquals (dateTime + "DEFAULT-1", tényleges); }}

Fontos bitek ebben a példában:

  • @RunWith a PowerMock-ot definiálja a teszt futójának
  • @PrepareForTest (osztály) felszólítja a PowerMockot, hogy készítse elő az osztályt későbbi feldolgozásra

Érdekes módon kérdezzük PowerMock hogy elcsúfítsa a privát módszert getCurrentDateTime (). A PowerMock a tükröződést fogja megtalálni, mert kívülről nem érhető el.

Így, amikor hívunk defaultImpl (), a privát módszerhez létrehozott csonkot a tényleges metódus helyett meghívjuk.

6. Nem absztrakt módszer, amely hozzáfér a példánymezőkhöz

Az absztrakt osztályok belső állapotát osztálymezőkkel lehet megvalósítani. A mezők értéke jelentősen befolyásolhatja a tesztelt módszert.

Ha egy mező nyilvános vagy védett, akkor könnyen elérhetjük a teszt módszerrel.

De ha privát, akkor használnunk kell PowerMockito:

public abstract class AbstractInstanceFields {védett int szám; privát logikai aktív = hamis; public abstract int abstractFunc (); public String testFunc () {if (count> 5) {return "Overflow"; } visszatér aktív? "Hozzáadva": "Letiltva"; }}

Itt a testFunc () metódus példányszintű mezőket használ számol és aktív mielőtt visszatér.

Teszteléskor testFunc (), megváltoztathatjuk a számol mező használatával érheti el a Mockito.

Másrészt, hogy tesztelje a viselkedést a magánemberrel aktív mezőben, megint használnunk kell PowerMockito, és annak Fehér doboz osztály:

@Test public void whenPowerMockitoAndActiveFieldTrue_thenCorrectBehaviour () {AbstractInstanceFields instClass = PowerMockito.mock (AbstractInstanceFields.class); PowerMockito.doCallRealMethod () .when (instClass) .testFunc (); Whitebox.setInternalState (instClass, "aktív", igaz); assertEquals ("Hozzáadva", instClass.testFunc ()); }

Csonk osztályt hozunk létre PowerMockito.mock (), és használjuk Fehér doboz osztály az objektum belső állapotának ellenőrzésére.

A. Értéke aktív mező megváltozott igaz.

7. Következtetés

Ebben az oktatóanyagban számos példát láthattunk, amelyek sok felhasználási esetre kiterjednek. Az elvárt osztályokat még több forgatókönyvben használhatjuk, a követett tervezéstől függően.

Ezenkívül az egység tesztek írása az absztrakt osztály módszerekhez ugyanolyan fontos, mint a normál osztályokhoz és módszerekhez. Mindegyiket tesztelhetjük különböző technikákkal vagy a rendelkezésre álló különböző teszt-támogató könyvtárakkal.

A teljes forráskód elérhető a GitHubon.