Különbség Stub, Mock és Spy között a Spock Framework-ben

1. Áttekintés

Ebben az oktatóanyagban megvitatjuk a különbségeket Gúny, Stub, és Kém a Spock keretében. Ábrázoljuk, mit kínál a keretrendszer az interakció alapú teszteléssel kapcsolatban.

Spock egy tesztelési keretrendszer a Jáva és Groovy ez segít automatizálni a szoftveralkalmazás manuális tesztelését. Bemutatja saját gúnyait, csonkjait és kémjeit, és beépített képességekkel rendelkezik olyan tesztekhez, amelyekhez általában további könyvtárakra van szükség.

Először bemutatjuk, hogy mikor kell használni a csonkokat. Aztán gúnyolódni fogunk. A végén leírjuk a nemrég bemutatottakat Kém.

2. Maven-függőségek

Mielőtt elkezdenénk, tegyük hozzá Maven-függőségeinket:

 org.spockframework spock-core 1.3-RC1-groovy-2.5 teszt org.codehaus.groovy groovy-all 2.4.7 teszt 

Vegye figyelembe, hogy szükségünk lesz a 1.3-RC1-groovy-2.5 Spock verziója. Kém a Spock Framework következő stabil verziójában kerül bemutatásra. Épp most Kém elérhető az 1.3-as verzió első kiadójelöltjében.

A Spock-teszt alapstruktúrájának összefoglalásához olvassa el a Groovy és Spock tesztelésével kapcsolatos bevezető cikkünket.

3. Interakció alapú tesztelés

Az interakció alapú tesztelés olyan technika, amely segít tesztelni az objektumok viselkedését - konkrétan, hogyan lépnek kapcsolatba egymással. Ehhez használhatunk ál-megvalósításnak nevezett dummy-megvalósításokat.

Természetesen nagyon egyszerűen megírhatnánk a gúnyok és csonkok saját megvalósításait. A probléma akkor jelenik meg, amikor a termelési kódunk mennyisége növekszik. A kód kézi megírása és karbantartása nehézkessé válik. Ezért gúnyos keretrendszereket használunk, amelyek tömör módon biztosítják a várható interakciók rövid leírását. A Spock beépített támogatással rendelkezik a gúnyolódáshoz, a botláshoz és a kémkedéshez.

A legtöbb Java könyvtárhoz hasonlóan a Spock is a JDK dinamikus proxyt használja az interfészek csúfolásához, a Byte Buddy vagy a cglib proxykat pedig a csúfoló osztályokhoz. Futtatási futtatásokat hoz létre futás közben.

A Java-nak már sok különböző és kiforrott könyvtára van az osztályok és interfészek kigúnyolására. Bár ezek mindegyike használható a Spockban, még mindig van egy fő oka annak, hogy Spock-gúnyokat, csonkokat és kémeket használjunk. Azáltal, hogy mindezeket bemutatta a Spocknak, kihasználhatjuk Groovy összes képességét hogy tesztjeink olvashatóbbá, könnyebben írhatóvá és mindenképpen szórakoztatóbbá váljanak!

4. Szúrási módszer hívások

Néha, az egységvizsgálatok során meg kell adnunk az osztály dummy viselkedését. Ez lehet egy kliens egy külső szolgáltatáshoz, vagy egy osztály, amely hozzáférést biztosít az adatbázishoz. Ezt a technikát makacsnak nevezik.

A csonk egy meglévő osztály kontrollálható cseréje függőség a tesztelt kódunkban. Ez hasznos egy olyan módszerhívás kezdeményezéséhez, amely bizonyos módon reagál. Amikor csonkot használunk, nem érdekel, hogy hányszor hívnak meg egy módszert. Ehelyett csak azt akarjuk mondani: adja vissza ezt az értéket, ha ezekkel az adatokkal hívják meg.

Térjünk át az üzleti logikával rendelkező példakódra.

4.1. Kód tesztelés alatt

Hozzunk létre egy modell osztályt Tétel:

public class Item {private final String id; privát végleges karakterlánc neve; // standard konstruktor, getters, egyenlő}

Felül kell írnunk a egyenlő (Object other) módszer állításaink működéséhez. Spock használni fogja egyenlő állítások során, amikor a kettős egyenlőségjelet használjuk (==):

új elem ('1', 'név') == új elem ('1', 'név')

Most hozzunk létre egy felületet ItemProvider egy módszerrel:

nyilvános felület ItemProvider {List getItems (List itemIds); }

Szükségünk lesz egy tesztelt osztályra is. Hozzáadunk egy ItemProvider függőségként ItemService:

public class ItemService {private final ItemProvider itemProvider; public ItemService (ItemProvider itemProvider) {this.itemProvider = itemProvider; } Lista getAllItemsSortedByName (Lista itemIds) {Lista elemek = itemProvider.getItems (itemIds); return items.stream () .sorted (Comparator.comparing (Item :: getName)) .collect (Collectors.toList ()); }}

Azt akarjuk, hogy kódunk egy absztrakciótól függjön, nem pedig egy konkrét megvalósítástól. Ezért használunk interfészt. Ennek sokféle megvalósítása lehet. Például olvashatunk elemeket egy fájlból, létrehozhatunk HTTP klienst a külső szolgáltatáshoz, vagy elolvashatjuk az adatokat egy adatbázisból.

Ebben a kódban el kell tüntetnünk a külső függőséget, mert csak a getAllItemsSortedByName módszer.

4.2. Eltöntött objektum használata a tesztelt kódban

Inicializáljuk a ItemService objektum a beállít() módszer a Stub a ItemProvider függőség:

ItemProvider itemProvider ItemService itemService def setup () {itemProvider = Stub (ItemProvider) itemService = új ItemService (itemProvider)}

Most, csináljuk itemProvider adjon vissza minden meghívás elemlistáját az adott argumentummal:

itemProvider.getItems (['offer-id', 'offer-id-2']) >> [új elem ('offer-id-2', 'Zname'), új elem ('offer-id', 'Aname ')]

A >> operandus segítségével elcsúsztatjuk a módszert. A getItems A metódus mindig két elem listáját adja vissza, amikor meghívják [’Ajánlat-azonosító’, ’ajánlat-azonosító-2’] lista. [] egy Groovy parancsikon a listák létrehozásához.

Itt van a teljes vizsgálati módszer:

def 'név szerint rendezett elemeket kell visszaadnia' () {megadott: def ids = ['offer-id', 'offer-id-2'] itemProvider.getItems (ids) >> [new Item ('offer-id-2 ',' Zname '), új elem (' offer-id ',' Aname ')] amikor: List items = itemService.getAllItemsSortedByName (ids) majd: items.collect {it.name} == [' Aname ',' Zname ']}

Sokkal több olyan kényszerítő képességet használhatunk, mint például: argumentumillesztési kényszerek használata, értékek sorozatainak használata csonkokban, eltérő viselkedés meghatározása bizonyos körülmények között, és a módszer válaszainak láncolása.

5. Gúnyolódási módszerek

Most beszéljünk az osztályok vagy interfészek gúnyolásáról a Spockban.

Néha, szeretnénk tudni, hogy a függő objektum valamilyen módszerét meghívtuk-e megadott argumentumokkal. A tárgyhívásokra szeretnénk összpontosítani, és a módszerhívásokra figyelve feltárni, hogyan hatnak egymással.A csúfolás a tesztosztály objektumai közötti kötelező kölcsönhatás leírása.

Az interakciókat az alább leírt példakódban teszteljük.

5.1. Kód interakcióval

Egyszerű példa: elemeket mentünk az adatbázisba. A siker után egy eseményt szeretnénk közzétenni az üzenetközvetítőn a rendszerünk új tételeiről.

Az üzenetközvetítő példa egy RabbitMQ vagy Kafka, így általában csak a szerződésünket írjuk le:

nyilvános felület EventPublisher {void publish (String addedOfferId); }

Tesztelési módszerünk nem üres elemeket ment el az adatbázisban, majd közzéteszi az eseményt. Az elem mentése az adatbázisba a példánkban lényegtelen, ezért csak megjegyzést fűzünk:

void saveItems (List itemIds) {List notEmptyOfferIds = itemIds.stream () .filter (itemId ->! itemId.isEmpty ()) .collect (Collectors.toList ()); // mentés az adatbázisba notEmptyOfferIds.forEach (eventPublisher :: publish); }

5.2. Kölcsönhatás ellenőrzése csúfolt objektumokkal

Most teszteljük a kódunk interakcióját.

Első, gúnyolódnunk kell EventPublisher miénkben beállít() módszer. Tehát alapvetően létrehozunk egy új példánymezőt, és a használatával kigúnyoljuk Gúny (osztály) funkció:

class Az ItemServiceTest kiterjeszti a Specifikációt {ItemProvider itemProvider

Most megírhatjuk vizsgálati módszerünket. 3 karakterláncot adunk át: ”,„ a ”,„ b ”, és azt várjuk, hogy a mi eventPublisher 2 eseményt tesz közzé „a” és „b” karakterláncokkal:

def 'kell közzétennie eseményeket az új, nem üresen mentett ajánlatokról' () {megadott: def offerIds = ['', 'a', 'b'] amikor: itemService.saveItems (offerIds), akkor: 1 * eventPublisher.publish (' a ') 1 * eventPublisher.publish (' b ')}

Vizsgáljuk meg közelebbről az állításunkat a döntőben azután szakasz:

1 * eventPublisher.publish ('a')

Arra számítunk itemService hívni fog egy eventPublisher.publish (karakterlánc) az „a” jelzéssel.

A csöppségben az érvek korlátozásáról beszéltünk. Ugyanezek a szabályok érvényesek a gúnyokra is. Ezt ellenőrizhetjük eventPublisher.publish (karakterlánc) kétszer hívták meg minden nem null és nem üres argumentummal:

2 * eventPublisher.publish ({it! = Null &&! It.isEmpty ()})

5.3. A gúnyolódás és a szúrás kombinálása

Ban ben Spock, a Gúny ugyanúgy viselkedhet, mint a Stub. Tehát azt mondhatjuk a csúfolt objektumoknak, hogy egy adott metódushíváshoz vissza kell adnia az adott adatot.

Írjuk felül ItemProvider val vel Gúny (osztály) és hozzon létre egy újat ItemService:

adott: itemProvider = Mock (ItemProvider) itemProvider.getItems (['item-id']) >> [új Item ('item-id', 'name')] itemService = új ItemService (itemProvider, eventPublisher) mikor: def elemek = itemService.getAllItemsSortedByName (['item-id']), majd: items == [új elem ('item-id', 'name')] 

Átírhatjuk a csonkolást a adott szakasz:

1 * itemProvider.getItems (['item-id']) >> [új elem ('item-id', 'name')]

Tehát általában ez a sor azt mondja: itemProvider.getItems egyszer hívják ['tárgy azonosító'] argumentum és a megadott tömb visszatérése.

Azt már tudjuk, hogy a gúnyok ugyanúgy viselkedhetnek, mint a csonkok. Az argumentumkorlátokra, a többértékes visszatérésre és a mellékhatásokra vonatkozó összes szabály vonatkozik ezekre is Gúny.

6. Kémkedő osztályok Spockban

A kémek lehetőséget nyújtanak egy meglévő objektum becsomagolására. Ez azt jelenti, hogy meghallgathatjuk a hívó és a valós objektum közötti beszélgetést, de megtarthatjuk az eredeti objektum viselkedését. Alapvetően, Kém delegálja a metódushívásokat az eredeti objektumra.

Szemben Gúny és Stub, nem hozhatunk létre a Kém egy felületen. Egy tényleges objektumot burkol, ezért emellett argumentumokat kell adnunk a konstruktor számára. Ellenkező esetben a típus alapértelmezett konstruktora lesz meghívva.

6.1. Kód tesztelés alatt

Hozzunk létre egy egyszerű megvalósítást a EventPublisher. LoggingEventPublisher kinyomtatja a konzolban minden hozzáadott elem azonosítóját. Íme az interfész módszer megvalósítása:

@Orride public void publish (String addedOfferId) {System.out.println ("Közzétettem:" + addedOfferId); }

6.2. Tesztelés Kém

Kémeket hozunk létre a gúnyokhoz és a csonkokhoz hasonlóan a Kém (osztály) módszer. LoggingEventPublisher nincs más osztályfüggősége, ezért nem kell átadnunk a konstruktor argumentumait:

eventPublisher = Kém (LoggingEventPublisher)

Most teszteljük kémünket. Új példányra van szükségünk ItemService kém tárgyunkkal:

adott: eventPublisher = Kém (LoggingEventPublisher) itemService = új ItemService (itemProvider, eventPublisher) mikor: itemService.saveItems (['item-id']), majd: 1 * eventPublisher.publish ('item-id')

Ellenőriztük, hogy a eventPublisher.publish módszert csak egyszer hívták meg. Ezenkívül a metódushívást továbbították a valódi objektumnak, így meglátjuk a kimenetét println a konzolban:

Közzétettem: item-id

Vegye figyelembe, hogy amikor a Kém, akkor nem hívja meg a valós objektum metódust. Általában kerülnünk kell a kémeket. Ha meg kell csinálnunk, talán átrendeznénk a kódot a specifikáció szerint?

7. Jó egységvizsgálatok

Végül egy gyors összefoglalással arról, hogy a csúfolt objektumok használata hogyan javítja tesztjeinket:

  • determinisztikus tesztcsomagokat hozunk létre
  • nem lesznek mellékhatásaink
  • egység tesztjeink nagyon gyorsak lesznek
  • koncentrálhatunk az egyetlen Java osztály logikájára
  • tesztjeink függetlenek a környezettől

8. Következtetés

Ebben a cikkben alaposan leírtuk a kémeket, a gúnyokat és a csonkokat Groovy-ban. A témával kapcsolatos ismeretek gyorsabbá, megbízhatóbbá és könnyebben olvashatóvá teszik tesztjeinket.

Valamennyi példánk megvalósítása megtalálható a Github projektben.


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