Napredno korištenje JMockita

1. Uvod

U ovom ćemo članku ići dalje od osnova JMockita i počet ćemo razmatrati neke napredne scenarije, kao što su:

  • Lažiranje (ili Maketa API)
  • The Deenkapsulacija klasa korisnosti
  • Kako se rugaju s više sučelja koristeći samo jedan lažni obrazac
  • Kako ponovno koristiti očekivanja i provjere

Ako želite otkriti JMockitove osnove, provjerite ostale članke iz ove serije. Relevantne poveznice možete pronaći na dnu stranice.

2. Ovisnost Mavena

Prvo ćemo trebati dodati jmockit ovisnost u naš projekt:

 org.jmockit jmockit 1,41 

Zatim ćemo nastaviti s primjerima.

3. Privatne metode / ruganje unutarnje nastave

Izrugivanje i testiranje privatnih metoda ili unutarnjih predavanja često se ne smatra dobrom praksom.

Razlog tome je da, ako su privatni, ne bi ih trebalo testirati izravno, jer su oni najdublje crijevo klase, ali ponekad to još treba učiniti, posebno kada se radi o naslijeđenom kodu.

S JMockitom imate dvije mogućnosti da ih riješite:

  • The Maketa API za promjenu stvarne implementacije (za drugi slučaj)
  • The Deenkapsulacija klasa korisnosti, za izravno pozivanje bilo koje metode (za prvi slučaj)

Svi sljedeći primjeri bit će izvedeni za sljedeću klasu i pretpostavit ćemo da se izvode na testnoj klasi s istom konfiguracijom kao i prva (da se izbjegne ponavljanje koda):

javni razred AdvancedCollaborator {int i; private int privateField = 5; // zadani konstruktor izostavljen javni AdvancedCollaborator (string niza) baca iznimku {i = string.length (); } public String methodThatCallsPrivateMethod (int i) {return privateMethod () + i; } public int methodThatReturnsThePrivateField () {return privateField; } private String privateMethod () {return "default:"; } klasa InnerAdvancedCollaborator {...}}

3.1. Pretvarajući se s Maketa

JMockit-ov Mockup API pruža podršku za stvaranje lažnih implementacija ili makete. Tipično, a maketa cilja nekoliko metoda i / ili konstruktora u klasi koje će se glumiti, dok većinu ostalih metoda i konstruktora ostavlja neizmijenjenim. To omogućuje potpuno prepisivanje klase, tako da se može ciljati bilo koja metoda ili konstruktor (s bilo kojim modifikatorom pristupa).

Pogledajmo kako možemo redefinirati privateMethod () pomoću Mockup API-ja:

@RunWith (JMockit.class) javna klasa AdvancedCollaboratorTest {@Tested private AdvancedCollaborator mock; @Test public void testToMockUpPrivateMethod () {new MockUp () {@Mock private String privateMethod () {return "mocked:"; }}; Niz res = mock.methodThatCallsPrivateMethod (1); assertEquals ("ismijani: 1", res); }}

U ovom primjeru definiramo novi Maketa za AdvancedCollaborator razred koristeći @Oponašanje bilješka na metodi s odgovarajućim potpisom. Nakon toga pozivi na tu metodu bit će dodijeljeni našoj izrugivanoj.

Ovo također možemo koristiti za maketa konstruktor klase kojoj su potrebni specifični argumenti ili konfiguracija kako bi se pojednostavili testovi:

@Test public void testToMockUpDifficultConstructor () baca izuzetak {new MockUp () {@Mock public void $ init (pozivanje u pozivu, niz niza) {((AdvancedCollaborator) invocation.getInvokedInstance ()). I = 1; }}; AdvancedCollaborator coll = novi AdvancedCollaborator (null); assertEquals (1, coll.i); }

U ovom primjeru možemo vidjeti da se za ismijavanje konstruktora morate rugati $ init metoda. Možete proslijediti dodatni argument tipa Poziv, pomoću koje možete pristupiti informacijama o pozivu ismijane metode, uključujući instancu na koju se poziva.

3.2. Koristiti Deenkapsulacija Razred

JMockit uključuje testnu uslužnu klasu: Deenkapsulacija. Kao što mu samo ime govori, koristi se za dekapsulaciju stanja objekta, a pomoću njega možete pojednostaviti testiranje pristupanjem poljima i metodama kojima se inače ne može pristupiti.

Možete se pozvati na metodu:

@Test public void testToCallPrivateMethodsDirectly () {Vrijednost objekta = Deencapsulation.invoke (mock, "privateMethod"); assertEquals ("zadani:", vrijednost); }

Također možete postaviti polja:

@Test public void testToSetPrivateFieldDirectly () {Deencapsulation.setField (lažno, "privateField", 10); assertEquals (10, mock.methodThatReturnsThePrivateField ()); }

I dobiti polja:

@Test public void testToGetPrivateFieldDirectly () {int value = Deencapsulation.getField (lažno, "privateField"); assertEquals (5, vrijednost); }

I stvorite nove instance klasa:

@Test public void testToCreateNewInstanceDirectly () {AdvancedCollaborator coll = Deencapsulation .newInstance (AdvancedCollaborator.class, "foo"); assertEquals (3, coll.i); }

Čak i novi primjeri unutarnjih klasa:

@Test public void testToCreateNewInnerClassInstanceDirectly () {InnerCollaborator inner = Deencapsulation .newInnerInstance (InnerCollaborator.class, mock); assertNotNull (unutarnji); }

Kao što vidite, Deenkapsulacija razred izuzetno je koristan pri testiranju nepropusnih sati. Jedan primjer mogao bi biti postavljanje ovisnosti klase koja koristi @Autowired napomene na privatnim poljima i za njih nema postavljača, niti za jedinstveno testiranje unutarnjih klasa, a da ne mora ovisiti o javnom sučelju klase spremnika.

4. Izrugivanje više sučelja u istoj rugi

Pretpostavimo da želite testirati klasu - koja još nije implementirana - ali sigurno znate da će implementirati nekoliko sučelja.

Obično ne biste mogli testirati spomenutu klasu prije nego što je implementirate, ali s JMockitom imate mogućnost unaprijed pripremiti testove rugajući se više od jednog sučelja pomoću jednog lažnog objekta.

To se može postići korištenjem generičkih sredstava i definiranjem tipa koji proširuje nekoliko sučelja. Ovaj generički tip može se definirati za cijelu klasu ispitivanja ili samo za jednu ispitnu metodu.

Na primjer, stvorit ćemo lažnu izvedbu za sučelja Popis i Usporedive dva puta:

@RunWith (JMockit.class) javna klasa AdvancedCollaboratorTest> {@Mocked privatni MultiMock multiMock; @Test public void testOnClass () {nova očekivanja () {{multiMock.get (5); rezultat = "foo"; multiMock.compareTo ((Popis) bilo koji); rezultat = 0; }}; assertEquals ("foo", multiMock.get (5)); assertEquals (0, multiMock.compareTo (novi ArrayList ())); } @Test javnosti > void testOnMethod (@Mocked M mock) {nova očekivanja () {{mock.get (5); rezultat = "foo"; mock.compareTo ((Popis) bilo koji); rezultat = 0; }}; assertEquals ("foo", mock.get (5)); assertEquals (0, mock.compareTo (novi ArrayList ())); }}

Kao što vidite u retku 2, možemo definirati novu vrstu testa za cijeli test korištenjem generičkih podataka na nazivu klase. Onuda, MultiMock bit će dostupan kao vrsta i moći ćete za to stvoriti podsmijehe koristeći bilo koju od JMockitovih bilješki.

U redovima od 7 do 18 možemo vidjeti primjer korištenja lažne višeklasne klase definirane za cijelu testnu klasu.

Ako vam je potrebna višestruka sučelja za samo jedan test, to možete postići definiranjem generičkog tipa na potpisu metode i dostavljanjem novog laga tog novog generičkog kao argument metode ispitivanja. U redovima 20 do 32 možemo vidjeti primjer za to za isto testirano ponašanje kao u prethodnom testu.

5. Ponovna upotreba očekivanja i provjera

Na kraju, prilikom testiranja nastave, možete se susresti sa slučajevima kada ponavljate isto Očekivanja i / ili Provjere uvijek iznova. Da biste to olakšali, obje možete lako ponovno upotrijebiti.

Objasnit ćemo to na primjeru (koristimo klase Model, suradnik, i Izvođač iz našeg članka JMockit 101):

@RunWith (JMockit.class) javna klasa ReusingTest {@Injectable private Collaborator suradnik; @Mocked model privatnog modela; @ Testirani izvođač izvođača; @Prije javnog void postavljanja () {nova očekivanja () {{model.getInfo (); rezultat = "foo"; minTimes = 0; suradnik.collaborate ("foo"); rezultat = točno; minTimes = 0; }}; } @Test public void testWithSetup () {performer.perform (model); verifyTrueCalls (1); } zaštićena praznina verifyTrueCalls (int pozivi) {nove provjere () {{suradnik.receive (istina); puta = pozivi; }}; } konačna klasa TrueCallsVerification proširuje provjere {public TrueCallsVerification (int pozivi) {suradnik.receive (true); puta = pozivi; }} @Test public void testWithFinalClass () {performer.perform (model); nova TrueCallsVerification (1); }}

U ovom primjeru možete vidjeti u redovima od 15 do 18 da pripremamo očekivanja za svaki test, tako da model.getInfo () uvijek se vraća "Foo" i za suradnik.saraditi() uvijek očekivati "Foo" kao argument i vraćanje pravi. Stavili smo minTimes = 0 izjava tako da se ne pojavljuju neuspjesi kada ih zapravo ne koristite u testovima.

Također, stvorili smo metodu verifyTrueCalls (int) radi pojednostavljenja provjera na suradnik.primiti (logički) metoda kada je proslijeđeni argument pravi.

Na kraju, možete stvoriti i nove vrste specifičnih očekivanja i provjera koje samo proširuju bilo koji od Očekivanja ili Provjere razreda. Zatim definirate konstruktor ako trebate konfigurirati ponašanje i stvoriti novu instancu spomenutog tipa u testu kao što to radimo u redovima od 33 do 43.

6. Zaključak

Ovim dijelom JMockit serije dotaknuli smo nekoliko naprednih tema koje će vam zasigurno pomoći u svakodnevnom ruganju i testiranju.

Možda ćemo objaviti više članaka o JMockitu, pa budite uz nas da biste saznali još više.

I kao i uvijek, potpunu provedbu ovog vodiča možete pronaći na GitHubu.

6.1. Članci u seriji

Svi članci serije:

  • JMockit 101
  • Vodič za JMockit očekivanja
  • Napredno korištenje JMockita