Mockito vs EasyMock vs JMockit

1. Bemutatkozás

1.1. Áttekintés

Ebben a bejegyzésben erről fogunk beszélni gúnyolódni: mi ez, miért kell használni, és számos példa arra, hogyan csúfolhatjuk meg ugyanazt a tesztesetet a Java leggyakrabban használt gúnyos könyvtárainak használatával.

Kezdjük a gúnyos fogalmak néhány formális / félalakos meghatározásával; majd bemutatjuk a tesztelt esetet, követünk példákat az egyes könyvtárakra, és néhány következtetést vonunk le. A kiválasztott könyvtárak a Mockito, az EasyMock és a JMockit.

Ha úgy érzi, hogy már ismeri a gúnyolás alapjait, talán átugorhatja a 2. pontot anélkül, hogy elolvassa volna a következő három pontot.

1.2. A gúnyok használatának okai

Kezdjük feltételezni, hogy már kódolt valamilyen tesztekre összpontosított vezérelt fejlesztési módszert (TDD, ATDD vagy BDD) követve. Vagy egyszerűen azt, hogy tesztet akar létrehozni egy létező osztály számára, amely függőségekre támaszkodik annak funkcionalitásának elérése érdekében.

Mindenesetre, ha osztálytesztelünk, akkor szeretnénk csak a funkcionalitását tesztelje, és ne a függőségeit (vagy azért, mert bízunk megvalósításukban, vagy mert magunk is teszteljük).

Ennek elérése érdekében biztosítanunk kell a tesztelés alatt álló objektum számára egy helyettesítést, amelyet ellenőrizhetünk az adott függőség szempontjából. Így kényszeríthetjük a szélsőséges visszatérési értékeket, a kivételdobást, vagy egyszerűen csökkenthetjük az időigényes módszereket fix visszatérési értékre.

Ez az ellenőrzött csere a gúnyolódni, és ez segít a tesztkódolás egyszerűsítésében és a teszt végrehajtási idejének csökkentésében.

1.3. Mintás fogalmak és meghatározás

Nézzünk meg négy meghatározást egy Martin Fowler által írt cikkből, amely összefoglalja az alapokat, amelyeket mindenkinek tudnia kell a gúnyokról:

  • Színlelt az objektumokat átadják, de soha nem használják fel őket. Általában csak a paraméterlisták kitöltésére szolgálnak.
  • Hamisítvány az objektumok működnek megvalósítással, de általában valamilyen parancsikont választanak, ami miatt nem alkalmasak a gyártásra (jó példa erre a memóriában lévő adatbázis).
  • Csonkok adjon konzerv válaszokat a teszt során kezdeményezett hívásokra, általában egyáltalán nem reagálnak semmire, ami a tesztre be van programozva. A csonkok rögzíthetnek információkat a hívásokról is, például egy e-mail átjáró csonkot, amely megjegyzi az „elküldött” üzeneteket, vagy csak azt, hogy hány üzenetet küldött el.
  • Gúnyok amelyekről itt beszélünk: olyan objektumok, amelyek előre be vannak programozva olyan elvárásokkal, amelyek meghatározzák a várható hívások specifikációját.

1.4 Gúnyolni vagy nem gúnyolni: Ez a kérdés

Nem kell mindent csúfolni. Néha jobb elvégezni az integrációs tesztet, mivel a módszer / szolgáltatás gúnyolódása csak kevés tényleges haszon érdekében működne. A tesztesetünkben (amelyet a következő pont mutat be), amely a LoginDao.

A LoginDao valamilyen harmadik fél könyvtárát használná a DB-hozzáféréshez, és annak kigúnyolása csak annak biztosításából állna, hogy paraméterek készültek a híváshoz, de akkor is tesztelnünk kell, hogy a hívás visszaadja-e a kívánt adatokat.

Ezért nem szerepel ebben a példában (bár írhatnánk mind az egységtesztet a harmadik fél könyvtárhívásainak meghívásával, mind pedig a DBUnittel integrációs tesztet a harmadik fél könyvtárának tényleges teljesítményének tesztelésére).

2. Teszteset

Az előző szakasz mindent szem előtt tartva tegyünk javaslatot egy meglehetősen tipikus tesztesetre és arra, hogy miként fogjuk tesztelni a gúnyok használatával (amikor van értelme gúnyokat használni). Ez segít abban, hogy közös forgatókönyvünk legyen, hogy később összehasonlíthassuk a különböző gúnyos könyvtárakat.

2.1 Javasolt eset

A javasolt teszteset a réteges architektúrájú alkalmazás bejelentkezési folyamata lesz.

A bejelentkezési kérelmet egy vezérlő kezeli, amely egy szolgáltatást használ, amely DAO-t használ (amely a felhasználói hitelesítő adatokat keresi a DB-n). Nem mélyülünk minden egyes réteg megvalósításában, és inkább a az összetevők közötti kölcsönhatások minden rétegből.

Így lesz egy LoginController, a LoginService és a LoginDAO. Lássunk egy diagramot a tisztázáshoz:

2.2 Végrehajtás

Most követjük a tesztesethez használt megvalósítást, hogy megértsük, mi történik (vagy mi történjen) a teszteken.

Kezdjük az összes művelethez használt modellel, UserForm, amely csak a felhasználó nevét és jelszavát fogja tárolni (az egyszerűsítéshez nyilvános hozzáférés-módosítókat használunk) és egy getter metódust a felhasználónév mező, amely lehetővé teszi az adott tulajdonság gúnyolását:

public class UserForm {public String jelszó; public String felhasználónév; public String getUsername () {return felhasználónév; }}

Kövessük LoginDAO, ez semmissé teszi a funkcionalitást, mivel csak azt akarjuk, hogy a módszerei ott legyenek, hogy szükség esetén gúnyolhassuk őket:

public class LoginDao {public int login (UserForm userForm) {return 0; }}

LoginDao által fogja használni LoginService annak Belépés módszer. LoginService lesz egy setCurrentUser visszatérő módszer üres hogy tesztelje azt a gúnyt.

public class LoginService {private LoginDao loginDao; privát karakterlánc currentUser; nyilvános logikai bejelentkezés (UserForm userForm) {assert null! = userForm; int loginResults = loginDao.login (userForm); kapcsoló (loginResults) {1. eset: return true; alapértelmezett: return false; }} public void setCurrentUser (String felhasználónév) {if (null! = felhasználónév) {this.currentUser = felhasználónév; }}}

Végül, LoginController használni fogja LoginService annak Belépés módszer. Ez magában foglalja:

  • egy olyan eset, amikor a megcsúfolt szolgáltatásra nem érkeznek hívások.
  • olyan eset, amelyben csak egy módszert hívnak meg.
  • olyan eset, amelyben az összes módszert meghívják.
  • olyan eset, amelyben kivételes dobást tesztelnek.
public class LoginController {public LoginService loginService; public String bejelentkezés (UserForm userForm) {if (null == userForm) {return "ERROR"; } else {logikai log log; próbálja meg a {logged = loginService.login (userForm) parancsot; } catch (e kivétel) {return "HIBA"; } if (naplózva) {loginService.setCurrentUser (userForm.getUsername ()); return "OK"; } else {return "KO"; }}}}

Most, hogy láttuk, mi az, amit megpróbálunk tesztelni, lássuk, hogyan fogjuk kigúnyolni ezt az egyes könyvtárakkal.

3. Tesztelje a telepítést

3.1 Mockito

A Mockito esetében a 2.8.9 verziót fogjuk használni.

A gúnyok létrehozásának és használatának legegyszerűbb módja a @Mock és @InjectMocks annotációk. Az első létrehoz egy modellt a mező meghatározásához használt osztály számára, a második pedig a létrehozott gúnyokat próbálja beinjekciózni az annotált makettbe.

Vannak még olyan kommentárok, mint pl @Kém amely lehetővé teszi részleges próbatétel létrehozását (olyan gúnyt, amely a kigúnyolt módszereknél a normál megvalósítást használja).

Ennek ellenére hívnia kell MockitoAnnotations.initMocks (ez) mielőtt bármilyen tesztet végrehajtana, amely felhasználná az említett gúnyokat mindezen „varázslatok” működéséhez. Ezt általában a @Előtt annotált módszer. Használhatja a MockitoJUnitRunner.

public class LoginControllerTest {@Mock private LoginDao loginDao; @Spy @InjectMocks privát LoginService spiedLoginService; @Mock privát LoginService loginService; @InjectMocks privát LoginController loginController; @ Nyilvános void előtt setUp () {loginController = new LoginController (); MockitoAnnotations.initMocks (ez); }}

3.2 EasyMock

Az EasyMock esetében a 3.4 (Javadoc) verziót fogjuk használni. Ne feledje, hogy az EasyMock alkalmazással telefonálnia kell, hogy a gúnyok „működni tudjanak” EasyMock.replay (gúny) minden vizsgálati módszerről, különben kivételt kap.

A csúfolódásokat és a tesztelt osztályokat annotációkkal is meghatározhatjuk, de ebben az esetben a statikus módszer meghívása helyett a EasyMockRunner a tesztosztályra.

A gúnyok a @Mock kommentár és a tesztelt objektum a @Tesztalany egyet (aminek függőségeit a létrehozott gúnyok injektálják). A tesztelt objektumot in-line kell létrehozni.

@RunWith (EasyMockRunner.class) public class LoginControllerTest {@Mock private LoginDao loginDao; @Mock privát LoginService loginService; @TestSubject privát LoginController loginController = új LoginController (); }

3.3. JMockit

A JMockit esetében az 1.24-es (Javadoc) verziót fogjuk használni, mivel az 1.25-ös verzió még nem jelent meg (legalábbis ennek megírása közben).

A JMockit telepítése ugyanolyan egyszerű, mint a Mockito esetében, azzal a kivétellel, hogy a részleges gúnyokhoz nincs külön megjegyzés (és valójában nincs is rá szükség), és ezt használnia kell JMockit mint tesztfutó.

A gúnyokat a @ Injekciós annotációval (amely csak egy próbapéldányt hoz létre) vagy a @Mocked annotáció (ez gúnyokat fog létrehozni az annotált mező osztályának minden példányához).

A tesztelt példány a (z) segítségével jön létre (és injektálják annak csúfolt függőségeit) @Tesztelve annotáció.

@RunWith (JMockit.class) public class LoginControllerTest {@Injectable private LoginDao loginDao; @ Injektálható privát LoginService loginService; @Tesztelt privát LoginController loginController; }

4. Annak ellenőrzése, hogy nincsenek-e gúnyolódások

4.1. Mockito

Annak ellenőrzésére, hogy egy gúny nem kapott-e hívást a Mockitóban, megvan a módszer VerifyZeroInteractions () hogy elfogad egy gúnyt.

@Test public void assertThatNoMethodHasBeenCalled () {loginController.login (null); Mockito.verifyZeroInteractions (loginService); }

4.2. EasyMock

Annak ellenőrzéséhez, hogy egy gúny nem kapott-e hívásokat, egyszerűen nem adja meg a viselkedését, újra játssza le a gúnyt, és végül ellenőrizze.

@Test public void assertThatNoMethodHasBeenCalled () {EasyMock.replay (loginService); loginController.login (null); EasyMock.verify (loginService); }

4.3. JMockit

Annak ellenőrzéséhez, hogy egy gúny nem kapott-e hívásokat, egyszerűen nem adja meg az elvárásait az adott gúttal kapcsolatban, és tegye a FullVerifications (ál) az említett gúnyért.

@Test public void assertThatNoMethodHasBeenCalled () {loginController.login (null); új FullVerifications (loginService) {}; }

5. A gúnyolt módszeres hívások meghatározása és a gúnyhívások ellenőrzése

5.1. Mockito

Mert gúnyos módszer hívások, Te tudod használni Mockito.when (mock.method (érvel)). AkkorReturn (érték). Itt egynél több híváshoz különböző értékeket adhat vissza, csak további paraméterként hozzáadva őket: thenReturn (value1, value2, value-n,…).

Ne feledje, hogy ezzel a szintaxissal nem csúfolhatja az érvénytelen visszatérési módszereket. Ezekben az esetekben az említett módszer igazolását használja (a 11. sorban látható módon).

Mert hívások ellenőrzése a felhasználható gúnyra Mockito.ellenőrzés (gúny) .módszer (érvek) és azt is ellenőrizheti, hogy a gombbal nem hívtak-e többé egy gúnyt VerifyNoMoreInteractions (ál).

Mert igazoló arg, átadhat meghatározott értékeket, vagy használhat előre definiált illesztőket, például Bármi(), anyString (), anyInt (). Sokkal több ilyen páros létezik, sőt lehetősége van meghatározni a párjait, amelyet a következő példákban láthatunk.

@Test public void assertTwoMethodsHaveBeenCalled () {UserForm userForm = new UserForm (); userForm.username = "foo"; Mockito.when (loginService.login (userForm)). ThenReturn (true); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); Mockito.verify (loginService) .login (userForm); Mockito.verify (loginService) .setCurrentUser ("foo"); } @Test public void assertOnlyOneMethodHasBeenCalled () {UserForm userForm = new UserForm (); userForm.username = "foo"; Mockito.when (loginService.login (userForm)). ThenReturn (hamis); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("KO", bejelentkezés); Mockito.verify (loginService) .login (userForm); Mockito.verifyNoMoreInteractions (loginService); }

5.2. EasyMock

Mert gúnyos módszer hívások, használod EasyMock.expect (mock.method (érvel)). ÉsReturn (érték).

Mert hívások ellenőrzése gúnyra, használhatja EasyMock.ellenőrzés (gúny), de hívnia kell mindig utána hívás EasyMock.replay (gúny).

Mert igazoló arg, átadhat meghatározott értékeket, vagy előre definiált egyezői vannak, mint például az isA(Class.class), anyString (), anyInt (), és még sok más ilyen típusú páros, és ismét lehetőség arra, hogy meghatározza a párjait.

@Test public void assertTwoMethodsHaveBeenCalled () {UserForm userForm = new UserForm (); userForm.username = "foo"; EasyMock.expect (loginService.login (userForm)). ÉsReturn (true); loginService.setCurrentUser ("foo"); EasyMock.replay (loginService); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); EasyMock.verify (loginService); } @Test public void assertOnlyOneMethodHasBeenCalled () {UserForm userForm = new UserForm (); userForm.username = "foo"; EasyMock.expect (loginService.login (userForm)). ÉsReturn (hamis); EasyMock.replay (loginService); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("KO", bejelentkezés); EasyMock.verify (loginService); }

5.3. JMockit

A JMockit segítségével meghatározta a tesztelés lépéseit: rögzítse, visszajátssza és ellenőrizze.

Rekord újban történik Elvárások(){{}} blokk (amelybe több gúthoz is meghatározhatsz műveleteket) visszajátszás egyszerűen a tesztelt osztály metódusának meghívásával történik (amelynek valamilyen csúfolt objektumot kell meghívnia), és igazolás egy új belsejében történik Ellenőrzések () {{}} blokk (amelybe több meghatást is meghatározhatunk).

Mert gúnyos módszer hívások, Te tudod használni gúny.módszer (érvel); eredmény = érték; bármelyiken belül Elvárások Blokk. Itt egynél több híváshoz különböző értékeket adhat vissza hozamok (value1, value2,…, valuen); ahelyett eredmény = érték;.

Mert hívások ellenőrzése gúnyra használhatja az új Ellenőrzéseket() {{mock.call (érték)}} vagy új ellenőrzések (ál) {{}} minden előzőleg definiált várható hívás ellenőrzéséhez.

Mert igazoló arg, átadhat meghatározott értékeket, vagy előre definiált értékeket, például Bármi, anyString, anyLong, és még sok más ilyen jellegű különleges érték, és ismét lehetőség arra, hogy meghatározzuk a párosokat (ezeknek Hamcrest-párosoknak kell lenniük).

@Test public void assertTwoMethodsHaveBeenCalled () {UserForm userForm = new UserForm (); userForm.username = "foo"; új várakozások () {{loginService.login (userForm); eredmény = igaz; loginService.setCurrentUser ("foo"); }}; Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); új FullVerifications (loginService) {}; } @Test public void assertOnlyOneMethodHasBeenCalled () {UserForm userForm = new UserForm (); userForm.username = "foo"; új várakozások () {{loginService.login (userForm); eredmény = hamis; // nem várható a setCurrentUser}}; Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("KO", bejelentkezés); új FullVerifications (loginService) {}; }

6. Gúnyos kivételdobás

6.1. Mockito

A kivételes dobást meg lehet csúfolni .thenThrow (ExceptionClass.class) után Mockito.when (mock.method (érvel)).

@Test public void mockExceptionThrowin () {UserForm userForm = new UserForm (); Mockito.when (loginService.login (userForm)). ThenThrow (IllegalArgumentException.class); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("HIBA", bejelentkezés); Mockito.verify (loginService) .login (userForm); Mockito.verifyZeroInteractions (loginService); }

6.2. EasyMock

A kivételes dobást meg lehet csúfolni .andThrow (új ExceptionClass ()) után egy EasyMock.expect (…) hívás.

@Test public void mockExceptionThrowing () {UserForm userForm = new UserForm (); EasyMock.expect (loginService.login (userForm)). AndThrow (új IllegalArgumentException ()); EasyMock.replay (loginService); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("HIBA", bejelentkezés); EasyMock.verify (loginService); }

6.3. JMockit

A JMockitóval való kivételes dobás gúnyolódása különösen könnyű. Csak a „normál” visszatérés helyett adja vissza a Kivételt egy kigúnyolt metódushívás eredményeként.

@Test public void mockExceptionThrowing () {UserForm userForm = new UserForm (); új várakozások () {{loginService.login (userForm); eredmény = új IllegalArgumentException (); // nem várható a setCurrentUser}}; Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("HIBA", bejelentkezés); új FullVerifications (loginService) {}; }

7. Körüljáró objektum gúnyolása

7.1. Mockito

Létrehozhat egy modellt, amelyet argumentumként átadhat egy metódushívásnak. A Mockito segítségével ezt egyhuzalos béléssel teheti meg.

@Test public void mockAnObjectToPassAround () {UserForm userForm = Mockito.when (Mockito.mock (UserForm.class) .getUsername ()) .thenReturn ("foo"). GetMock (); Mockito.when (loginService.login (userForm)). ThenReturn (true); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); Mockito.verify (loginService) .login (userForm); Mockito.verify (loginService) .setCurrentUser ("foo"); }

7.2. EasyMock

Gúnyok hozhatók létre összhangban EasyMock.mock (Class.class). Utána használhatja EasyMock.expect (mock.method ()) hogy előkészítse a végrehajtásra, mindig emlékezzen a hívásra EasyMock.replay (gúny) mielőtt felhasználná.

@Test public void mockAnObjectToPassAround () {UserForm userForm = EasyMock.mock (UserForm.class); EasyMock.expect (userForm.getUsername ()). AndReturn ("foo"); EasyMock.expect (loginService.login (userForm)). ÉsReturn (true); loginService.setCurrentUser ("foo"); EasyMock.replay (userForm); EasyMock.replay (loginService); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); EasyMock.verify (userForm); EasyMock.verify (loginService); }

7.3. JMockit

Ha egy objektumot csak egyetlen módszerrel akarunk kigúnyolni, egyszerűen átadhatjuk azt paraméterként kigúnyolva a vizsgálati módszernek. Ezután várakozásokat teremthet, mint bármely más gúny esetén.

@Test public void mockAnObjectToPassAround (@Mocked UserForm userForm) {new Expectations () {{userForm.getUsername (); eredmény = "foo"; loginService.login (userForm); eredmény = igaz; loginService.setCurrentUser ("foo"); }}; Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); új FullVerifications (loginService) {}; új FullVerifications (userForm) {}; }

8. Egyéni argumentumillesztés

8.1. Mockito

Néha a csúfolt hívások argumentumillesztésének valamivel összetettebbnek kell lennie, mint egy fix értéknek vagy anyString (). Erre az esetre a Mockito rendelkezik a matcher osztályával, amelyet együtt használnak argThat (ArgumentMatcher).

@Test public void argumentMatching () {UserForm userForm = new UserForm (); userForm.username = "foo"; // alapértelmezett egyező Mockito.when (loginService.login (Mockito.any (UserForm.class))). thenReturn (true); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); Mockito.verify (loginService) .login (userForm); // összetett egyező Mockito.verify (loginService) .setCurrentUser (ArgumentMatchers.argThat (új ArgumentMatcher () {@ Nyilvános logikai egyezések felülírása (String argumentum {return argument.startsWith ("foo");}})); }

8.2. EasyMock

Az egyéni argumentumillesztés egy kicsit bonyolultabb az EasyMock esetében, mivel létre kell hoznia egy statikus módszert, amelyben létrehozza a tényleges illesztőt, majd jelentést készít vele EasyMock.reportMatcher (IArgumentMatcher).

Miután létrehozta ezt a módszert, akkor ezt a megalapozott elvárásai szerint használja a módszer meghívásával (mint a sorban látható példában látható).

@Test public void argumentMatching () {UserForm userForm = new UserForm (); userForm.username = "foo"; // alapértelmezett egyező EasyMock.expect (loginService.login (EasyMock.isA (UserForm.class))). ésReturn (true); // összetett egyező loginService.setCurrentUser (specificArgumentMatching ("foo")); EasyMock.replay (loginService); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); EasyMock.verify (loginService); } privát statikus karakterlánc specificArgumentMatching (karakterlánc várható) {EasyMock.reportMatcher (új IArgumentMatcher () {@Orride public logikai egyezések (Object argument) {return argument instanceof String && ((String) argumentum) .startsWith (várható);} @Override public void appendTo (StringBuffer puffer) {// NOOP}}); return null; }

8.3. JMockit

A JMockit egyedi egyeztetése a speciális paranccsal történik withArgThat (Matcher) módszer (amely megkapja a Hamcrest Matcher tárgyak).

@Test public void argumentMatching () {UserForm userForm = new UserForm (); userForm.username = "foo"; // alapértelmezett egyező új Várakozások () {{loginService.login ((UserForm) bármely); eredmény = igaz; // complex matcher loginService.setCurrentUser (withArgThat (new BaseMatcher () {@ Nyilvános logikai egyezések felülbírálása (Object item) {String && ((String) elem) return return példánya .startsWith ("foo");} @Orride public void descriptionTo (Leírás leírása) {// NOOP}})); }}; Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); új FullVerifications (loginService) {}; }

9. Részleges gúny

9.1. Mockito

A Mockito kétféleképpen teszi lehetővé a részleges gúnyolódást (olyan gúnyt, amely a valódi megvalósítást használja a gúnyolt metódus-hívások helyett néhány módszerében).

Használhatja akár .thenCallRealMethod () normál modell módszerrel hívásdefiníció, vagy létrehozhat egy kém gúny helyett ebben az esetben az alapértelmezett viselkedés az lesz, hogy a valódi megvalósítást hívja meg minden nem gúnyolt módszerben.

@Test public void részlegesMocking () {// használja a részleges álhír loginController.loginService = spiedLoginService; UserForm userForm = new UserForm (); userForm.username = "foo"; // hagyjuk, hogy a szolgáltatás bejelentkezése használja a megvalósítást, így gúnyolódjunk a DAO hívásától a Mockito.when (loginDao.login (userForm)). thenReturn (1); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); // gúnyolt hívás ellenőrzése Mockito.verify (spiedLoginService) .setCurrentUser ("foo"); }

9.2. EasyMock

A részleges gúnyolódás az EasyMock használatával is kissé bonyolultabbá válik, mivel meg kell határoznia, hogy mely módszereket fogják kigúnyolni az ál létrehozásakor.

Ez azzal történik EasyMock.partialMockBuilder (Class.class) .addMockedMethod („methodName”). CreateMock (). Ha ez megtörtént, akkor használhatja a modellt bármely más, nem részleges modellként.

@Test public void részlegesMocking () {UserForm userForm = new UserForm (); userForm.username = "foo"; // részleges csúfolás használata LoginService loginServicePartial = EasyMock.partialMockBuilder (LoginService.class) .addMockedMethod ("setCurrentUser"). createMock (); loginServicePartial.setCurrentUser ("foo"); // hagyjuk, hogy a szolgáltatás bejelentkezése felhasználja a megvalósítást, így csúfoljuk meg a DAO hívást az EasyMock.expect (loginDao.login (userForm)). andReturn (1); loginServicePartial.setLoginDao (loginDao); loginController.loginService = loginServicePartial; EasyMock.replay (loginDao); EasyMock.replay (loginServicePartial); Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); // gúnyolt hívás ellenőrzése EasyMock.verify (loginServicePartial); EasyMock.verify (loginDao); }

9.3. JMockit

A részleges gúnyolódás a JMockittal különösen könnyű. Minden olyan metódushívás, amelyhez nem definiáltak csúfolt viselkedést a Elvárások(){{}} használ az „igazi” megvalósítás.

Most képzeljük el, hogy részben meg akarjuk csúfolni a LoginService osztály gúnyolódni a setCurrentUser () módszer, miközben a Belépés() módszer.

Ehhez először létrehozunk és átadunk egy példányt LoginService az elvárások blokkjához. Ezután csak egy várakozást rögzítünk a setCurrentUser () módszer:

@Test public void részlegesMocking () {LoginService részlegesLoginService = új LoginService (); részlegesLoginService.setLoginDao (loginDao); loginController.loginService = részlegesLoginService; UserForm userForm = new UserForm (); userForm.username = "foo"; új várakozások (részlegesLoginService) {{// gúnyolódjunk a DAO hívás loginDao.login (userForm); eredmény = 1; // nincs várakozás a bejelentkezési módszerre, hogy a valós megvalósítást használják // mock setCurrentUser hívás részleges LoginService.setCurrentUser ("foo"); }}; Karakterlánc bejelentkezés = loginController.login (userForm); Assert.assertEquals ("OK", bejelentkezés); // igazolja a csúfolt hívást új Verifications () {{particLoginService.setCurrentUser ("foo"); }}; }

10. Következtetés

Ebben a bejegyzésben három Java próbatárat hasonlítottunk össze, mindegyik erősségeivel és hátrányaival együtt.

  • Mindhárman azok könnyen konfigurálható jelölésekkel, amelyek segítenek meghatározni a gúnyokat és a tesztelt objektumot, a futók pedig a gúnyfecskendezést a lehető legkevésbé fájdalommentessé teszik.
    • Azt mondanánk, hogy a Mockito nyer itt, mivel a részleges csúfolódásokhoz van egy speciális megjegyzés, de a JMockitnak nincs is szüksége rá, szóval tegyük fel, hogy ez kettő között holtverseny.
  • Mindhárman nagyjából követik a rekord-visszajátszás-igazolási minta, de véleményünk szerint a legjobb erre a JMockit, mivel arra kényszeríti, hogy blokkokban használja ezeket, így a tesztek strukturáltabbá válnak.
  • Könnyűség A felhasználás fontos, így minél kevesebbet dolgozhat a tesztek meghatározásán. A JMockit lesz a választott opció a fix-mindig ugyanazon struktúrához.
  • A Mockito többé-kevésbé A legismertebb, így a közösség nagyobb lesz.
  • Fel kell hívnom visszajátszás minden alkalommal, amikor gúnyt akarsz használni, egyértelmű no-go, így mínuszt adunk az EasyMock számára.
  • Következetesség / egyszerűség nekem is fontos. Imádtuk a JMockit eredményeinek visszaküldésének módját, amely megegyezik a „normál” eredmények, mint a kivételekkel.

Ha mindezt elmondjuk, választani fogunk JMockit egyfajta győztesként, annak ellenére, hogy eddig is használtuk Mockito mivel az egyszerűség és a rögzített szerkezet magával ragadott minket, és mostantól megpróbáljuk használni.

A teljes végrehajtása ennek az oktatóanyagnak a GitHub projektjén található meg, ezért nyugodtan töltse le és játsszon vele.


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