Testiranje apstraktne nastave s JUnit-om

1. Pregled

U ovom ćemo uputstvu analizirati različite slučajeve upotrebe i moguća alternativna rješenja za jedinično testiranje apstraktnih klasa neapstraktnim metodama.

Imajte na umu da testiranje apstraktnih klasa trebalo bi gotovo uvijek proći kroz javni API konkretnih implementacija, zato nemojte primjenjivati ​​dolje navedene tehnike ako niste sigurni što radite.

2. Ovisnosti Mavena

Počnimo s Mavenovim ovisnostima:

 org.junit.jupiter junit-jupiter-motor 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 

Najnovije verzije ovih knjižnica možete pronaći na Maven Central.

Powermock nije u potpunosti podržan za Junit5. Također, powermock-module-junit4 koristi se samo za jedan primjer predstavljen u odjeljku 5.

3. Neovisna apstraktna metoda

Razmotrimo slučaj kada imamo apstraktni razred s javnom apstraktnom metodom:

javni sažetak klase AbstractIndependent {javni sažetak int abstractFunc (); javni String defaultImpl () {return "DEFAULT-1"; }}

Želimo testirati metodu defaultImpl (), a imamo dva moguća rješenja - pomoću betonske klase ili pomoću Mockita.

3.1. Korištenje betonske klase

Stvorite konkretnu klasu koja se proteže SažetakNeovisno razreda i upotrijebite ga za testiranje metode:

javna klasa ConcreteImpl proširuje AbstractIndependent {@Override public int abstractFunc () {return 4; }}
@Test javna praznina givenNonAbstractMethod_whenConcreteImpl_testCorrectBehaviour () {ConcreteImpl conClass = new ConcreteImpl (); Niz stvarni = conClass.defaultImpl (); assertEquals ("DEFAULT-1", stvarno); }

Nedostatak ovog rješenja je potreba za stvaranjem konkretne klase s lažnim implementacijama svih apstraktnih metoda.

3.2. Koristeći Mockito

Alternativno, možemo koristiti Mockito za stvaranje lažne slike:

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

Ovdje je najvažniji dio priprema makete za upotrebu stvarnog koda kada se poziva metoda koristeći Mockito.CALLS_REAL_METHODS.

4. Apstraktna metoda pozvana iz apstraktne metode

U ovom slučaju, ne-apstraktna metoda definira globalni tijek izvršenja, dok se apstraktna metoda može napisati na različite načine, ovisno o slučaju upotrebe:

javni sažetak klase AbstractMethodCalling {javni sažetak String abstractFunc (); javni String defaultImpl () {Niz res = abstractFunc (); povratak (res == null)? "Zadano": (res + "Zadano"); }}

Da bismo testirali ovaj kôd, možemo koristiti ista dva pristupa kao i prije - ili stvoriti konkretnu klasu ili upotrijebiti Mockito za izradu lažne slike:

@Test javna praznina givenDefaultImpl_whenMockAbstractFunc_thenExpectedBehaviour () {AbstractMethodCalling cls = Mockito.mock (AbstractMethodCalling.class); Mockito.when (cls.abstractFunc ()). ThenReturn ("Sažetak"); Mockito.doCallRealMethod () .when (cls) .defaultImpl (); assertEquals ("Zadani sažetak", cls.defaultImpl ()); }

Evo, abstractFunc () je zakrčen povratnom vrijednošću koju preferiramo za test. To znači da kad zovemo neastraktnu metodu defaultImpl (), koristit će ovaj stub.

5. Neapstraktna metoda s ispitnim preprekama

U nekim scenarijima metoda koju želimo testirati poziva privatnu metodu koja sadrži testnu prepreku.

Moramo zaobići opstruktivnu metodu ispitivanja prije testiranja ciljne metode:

javni sažetak klase AbstractPrivateMethods {javni sažetak int abstractFunc (); javni niz defaultImpl () {return getCurrentDateTime () + "DEFAULT-1"; } private String getCurrentDateTime () {return LocalDateTime.now (). toString (); }}

U ovom primjeru, defaultImpl () metoda poziva privatnu metodu getCurrentDateTime (). Ova privatna metoda dobiva trenutno vrijeme u vrijeme izvođenja, što bi trebalo izbjegavati u našim jediničnim testovima.

Sada, da bismo se rugali standardnom ponašanju ove privatne metode, ne možemo ni koristiti Mockito jer ne može kontrolirati privatne metode.

Umjesto toga, trebamo koristiti PowerMock (nNapomena: ovaj primjer radi samo s JUnit 4 jer podrška za ovu ovisnost nije dostupna za JUnit 5):

@RunWith (PowerMockRunner.class) @PrepareForTest (AbstractPrivateMethods.class) javna klasa AbstractPrivateMethodsUnitTest {@Test javna praznina kadaMockPrivateMethod_thenVerifyBehaviour () {AbstractPrivateMethods mockClass = PowerMockclassito PowerMockito.doCallRealMethod () .when (mockClass) .defaultImpl (); Niz dateTime = LocalDateTime.now (). ToString (); PowerMockito.doReturn (dateTime) .when (mockClass, "getCurrentDateTime"); Niz stvarni = mockClass.defaultImpl (); assertEquals (dateTime + "DEFAULT-1", stvarno); }}

Važni dijelovi u ovom primjeru:

  • @RunWith definira PowerMock kao pokretač testa
  • @PrepareForTest (razred) govori PowerMocku da pripremi nastavu za kasniju obradu

Zanimljivo, pitamo PowerMock ugroziti privatnu metodu getCurrentDateTime (). PowerMock će upotrijebiti odraz kako bi ga pronašao jer mu nije dostupan izvana.

Tako, kad nazovemo defaultImpl (), umjesto stvarne metode pozvat će se klica stvorena za privatnu metodu.

6. Neapstraktna metoda koja pristupa poljima instance

Apstraktne klase mogu imati unutarnje stanje implementirano s poljima klasa. Vrijednost polja mogla bi imati značajan utjecaj na metodu koja se ispituje.

Ako je polje javno ili zaštićeno, možemo mu lako pristupiti putem metode ispitivanja.

Ali ako je privatno, moramo koristiti PowerMockito:

javna apstraktna klasa AbstractInstanceFields {zaštićen int count; privatna logička vrijednost active = false; javni sažetak int abstractFunc (); javni String testFunc () {if (count> 5) {return "Prelijevanje"; } povratak aktivan? "Dodano": "Blokirano"; }}

Evo, testFunc () metoda koristi polja na razini instance računati i aktivan prije nego što se vrati.

Prilikom ispitivanja testFunc (), možemo promijeniti vrijednost računati polje pristupom instanci stvorenoj pomoću Mockito.

S druge strane, testirati ponašanje s privatnim aktivan polje, morat ćemo opet koristiti PowerMockito, I je Bijela kutija razred:

@Test javna praznina kadaPowerMockitoAndActiveFieldTrue_thenCorrectBehaviour () {AbstractInstanceFields instClass = PowerMockito.mock (AbstractInstanceFields.class); PowerMockito.doCallRealMethod () .when (instClass) .testFunc (); Whitebox.setInternalState (instClass, "active", true); assertEquals ("Dodano", instClass.testFunc ()); }

Izrađujemo klasu klatna pomoću PowerMockito.mock ()i koristimo Bijela kutija klasa za kontrolu unutarnjeg stanja objekta.

Vrijednost aktivan polje se mijenja u pravi.

7. Zaključak

U ovom uputstvu vidjeli smo više primjera koji pokrivaju puno slučajeva korištenja. Apstraktne klase možemo koristiti u mnogim drugim scenarijima, ovisno o dizajnu koji slijedi.

Također, pisanje jedinstvenih testova za apstraktne metode predavanja jednako je važno kao i za uobičajene razrede i metode. Svakog od njih možemo testirati pomoću različitih tehnika ili različitih dostupnih knjižnica za podršku testiranju.

Cjeloviti izvorni kod dostupan je na GitHubu.