Programiranje

Mocks And Stubs - Razumevanje testnih dvojic z Mockito

Pogosto se srečam s tem, da ekipe, ki uporabljajo posmehljiv okvir, domnevajo, da se posmehujejo.

Ne zavedajo se, da so posmehi le ena izmed številnih "testnih dvojic", ki jih je Gerard Meszaros razvrstil na xunitpatterns.com.

Pomembno je vedeti, da ima vsaka vrsta testnega dvojnika pri testiranju drugačno vlogo. Na enak način, kot se morate naučiti različnih vzorcev ali refaktoringa, morate razumeti primitivne vloge vsake vrste testnega dvojnika. Nato jih lahko kombinirate, da dosežete svoje potrebe po testiranju.

Zajel bom zelo kratko zgodovino, kako je prišlo do te razvrstitve in kako se vsaka od vrst razlikuje.

To bom naredil z nekaj kratkimi, preprostimi primeri v Mockitu.

Ljudje že leta pišejo lahke različice sistemskih komponent za pomoč pri testiranju. Na splošno se je imenovalo škrtanje. Leta 2000 je članek "Endo-Testiranje: enotno testiranje z lažnimi predmeti" predstavil koncept lažnega predmeta. Od takrat je Stubs, Mocks in številne druge vrste testnih predmetov Meszaros uvrstil med testne dvojice.

Martin Fowler se je na to terminologijo skliceval v "Mocks Aren't Stubs" in je sprejet znotraj Microsoftove skupnosti, kot je prikazano v "Raziskovanje kontinuuma testnih dvojic"

Povezava do vsakega od teh pomembnih prispevkov je prikazana v referenčnem poglavju.

Zgornji diagram prikazuje najpogosteje uporabljene vrste testnih dvojnic. Naslednji URL daje dober navzkrižni sklic na vsak od vzorcev in njihovih značilnosti ter alternativno terminologijo.

//xunitpatterns.com/Test%20Double.html

Mockito je testni vohunski okvir in se ga je zelo enostavno naučiti. Pri Mockitu je treba omeniti, da pričakovanja kakršnih koli lažnih predmetov niso določena pred testom, saj so včasih v drugih posmehljivih okvirih. To vodi do bolj naravnega sloga (IMHO), ko se začnemo posmehovati.

Naslednji primeri so tukaj zgolj za preprost prikaz uporabe Mockita za izvajanje različnih vrst testnih dvojic.

Na spletnem mestu je veliko več konkretnih primerov, kako uporabljati Mockito.

//docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html

Spodaj je nekaj osnovnih primerov uporabe Mockita za prikaz vloge vsakega testnega dvojnika, kot jo je določil Meszaros.

Za vsako sem vključil povezavo do glavne definicije, tako da lahko dobite več primerov in popolno definicijo.

//xunitpatterns.com/Dummy%20Object.html

To je najpreprostejši testni dvojnik. To je objekt, ki nima izvedbe in se uporablja zgolj za zapolnitev argumentov klicev metode, ki za vaš test niso pomembni.

Na primer, spodnja koda uporablja veliko kode za ustvarjanje kupca, kar za test ni pomembno.

Preizkusu ni bilo vseeno, katera stranka bo dodana, če se število strank vrne kot ena.

javni kupec createDummyCustomer () {County County = new County ("Essex"); City city = novo mesto ("Romford", okrožje); Naslov naslov = nov naslov ("1234 Bank Street", mesto); Stranka stranka = nova stranka ("john", "dobie", naslov); povratna stranka; } @Test javna void addCustomerTest () {Lutka kupca = createDummyCustomer (); AddressBook addressBook = nov adresar (); addressBook.addCustomer (lutka); assertEquals (1, addressBook.getNumberOfCustomers ()); } 

Pravzaprav nas ne zanima vsebina predmeta kupca - vendar je to obvezno. Lahko poskusimo z ničelno vrednostjo, vendar če je koda pravilna, pričakujete, da bo vržena neka izjema.

@Test (pričakovano = Exception.class) public void addNullCustomerTest () {Lutka stranke = null; AddressBook addressBook = nov adresar (); addressBook.addCustomer (lutka); } 

Da bi se temu izognili, lahko uporabimo preprosto lutko Mockito, da dosežemo želeno vedenje.

@Test public void addCustomerWithDummyTest () {Lutka stranke = lažno (Customer.class); AddressBook addressBook = nov adresar (); addressBook.addCustomer (lutka); Assert.assertEquals (1, addressBook.getNumberOfCustomers ()); } 

Ta preprosta koda ustvari preskusni predmet, ki ga želite prenesti v klic.

Lutka kupca = lažno (Customer.class);

Naj vas lažna sintaksa ne zavede - tu se igra vloga lutke, ne posmeha.

Vloga testnega dvojnika je tista, ki ga ločuje, ne pa sintaksa, uporabljena za njegovo ustvarjanje.

Ta razred deluje kot preprost nadomestek za razred kupcev in olajša branje testa.

//xunitpatterns.com/Test%20Stub.html

Vloga preizkusnega droga je vrniti nadzorovane vrednosti predmetu, ki ga testiramo. Ti so opisani kot posredni vložki v test. Upajmo, da bo primer pojasnil, kaj to pomeni.

Vzemite naslednjo kodo

javni razred SimplePricingService izvaja PricingService {repozitorij PricingRepository; javni SimplePricingService (PricingRepository pricingRepository) {this.repository = pricingRepository; } @Override public Price priceTrade (trgovina) {return repository.getPriceForTrade (trgovina); } @Override public Price getTotalPriceForTrades (Zbirke) {Price totalPrice = new Price (); for (Trade trade: trades) {Price tradePrice = repository.getPriceForTrade (trade); totalPrice = totalPrice.add (tradePrice); } vrnitev totalPrice; } 

SimplePricingService ima en predmet sodelovanja, ki je repozitorij poslov. Repozitorij sklenjenih poslov zagotavlja cenovne storitve za storitve določanja cen prek metode getPriceForTrade.

Da bomo lahko preizkusili logiko poslov v SimplePricingService, moramo nadzorovati te posredne vnose

torej vložki, ki jih nikoli nismo prestali v test.

To je prikazano spodaj.

V naslednjem primeru zataknemo PricingRepository, da vrne znane vrednosti, ki jih lahko uporabimo za preizkus poslovne logike storitve SimpleTradeService.

@Test public void testGetHighestPricedTrade () vrže izjemo {Price price1 = new Price (10); Cena cena2 = nova Cena (15); Cena cene3 = novo Cena (25); PricingRepository pricingRepository = lažno (PricingRepository.class); kdaj (pricingRepository.getPriceForTrade (kateri koli (Trade.class))). thenReturn (price1, price2, price3); Storitev PricingService = nova SimplePricingService (pricingRepository); Cena najvišjaCena = storitev.getHighestPricedTrade (getTrades ()); assertEquals (price3.getAmount (), maximumPrice.getAmount ()); } 

Primer saboterja

Obstajata 2 pogosti različici preizkusnih pik: Responder's in Saboteur's.

Odzivniki se uporabljajo za preizkušanje srečne poti kot v prejšnjem primeru.

Za preizkušanje izjemnega vedenja, kot je prikazano spodaj, se uporablja saboter

@Test (pričakovano = TradeNotFoundException.class) public void testInvalidTrade () vrže izjemo {Trade trade = new FixtureHelper (). GetTrade (); TradeRepository tradeRepository = lažno (TradeRepository.class); kdaj (tradeRepository.getTradeById (anyLong ())). thenThrow (new TradeNotFoundException ()); TradingService tradingService = nova SimpleTradingService (tradeRepository); tradingService.getTradeById (trade.getId ()); } 

//xunitpatterns.com/Mock%20Object.html

Lažni predmeti se uporabljajo za preverjanje vedenja predmetov med preskusom. Z vedenjem objektov mislim, da preverimo, ali se ob izvajanju testa na predmetu izvajajo pravilne metode in poti.

To se zelo razlikuje od podporne vloge škrbine, ki se uporablja za zagotavljanje rezultatov za vse, kar preizkušate.

V škrbini uporabljamo vzorec definiranja vrnjene vrednosti metode.

when (customer.getSurname ()). thenReturn (priimek); 

V lažni obliki preverimo obnašanje predmeta z naslednjo obliko.

verify (listMock) .add (s); 

Tu je preprost primer, ko želimo preizkusiti, ali je nova trgovina pravilno revidirana.

Tu je glavna koda.

javni razred SimpleTradingService izvaja TradingService {TradeRepository tradeRepository; AuditService auditService; public SimpleTradingService (TradeRepository tradeRepository, AuditService auditService) {this.tradeRepository = tradeRepository; this.auditService = auditService; } public Long createTrade (trgovina) vrže CreateTradeException {Long id = tradeRepository.createTrade (trgovina); auditService.logNewTrade (trgovina); vrnitev id; } 

Spodnji test ustvari škrbino za repozitorij poslov in lažno za AuditService

Nato pokličemo preverjanje na izmišljeni AuditService, da se prepričamo, da TradeService to pokliče

logNewTrade pravilno

@Mock TradeRepository tradeRepository; @Mock AuditService auditService; @Test public void testAuditLogEntryMadeForNewTrade () vrže izjemo {Trade trade = new Trade ("Ref 1", "Description 1"); kdaj (tradeRepository.createTrade (trgovina)). thenReturn (anyLong ()); TradingService tradingService = nova SimpleTradingService (tradeRepository, auditService); tradingService.createTrade (trgovina); verify (auditService) .logNewTrade (trgovina); } 

V naslednji vrstici je preverjanje izmišljene AuditService.

verify (auditService) .logNewTrade (trgovina);

Ta test nam omogoča, da pokažemo, da se revizijska služba obnašanja pravilno obnaša.

//xunitpatterns.com/Test%20Spy.html

Za natančno opredelitev testnega vohuna je vredno pogledati zgornjo povezavo.

Vendar pa ga v programu Mockito rad uporabljam, da vam omogoči zavijanje resničnega predmeta in nato preverjanje ali spreminjanje njegovega vedenja v podporo vašemu testiranju.

Tu je primer, ko smo preverili standardno vedenje seznama. Upoštevajte, da lahko oba preverimo, ali je bila dodana metoda add, in tudi trdimo, da je bil element dodan na seznam.

@Spy List listSpy = new ArrayList (); @Test public void testSpyReturnsRealValues ​​() vrže izjemo {String s = "dobie"; listSpy.add (novi niz); verify (listSpy) .add (s); assertEquals (1, listSpy.size ()); } 

Primerjajte to z uporabo lažnega predmeta, pri katerem je mogoče preveriti samo klic metode. Ker se norčujemo samo iz vedenja seznama, ne zabeleži, da je bil element dodan, in vrne privzeto vrednost nič, ko pokličemo metodo size ().

@Mock List listMock = new ArrayList (); @Test public void testMockReturnsZero () vrže izjemo {String s = "dobie"; listMock.add (novi niz); verify (listMock) .add (s); assertEquals (0, listMock.size ()); } 

Druga koristna lastnost testSpy je sposobnost omamljanja povratnih klicev. Ko je to storjeno, se bo objekt obnašal normalno, dokler ne pokličete metode stubbed.

V tem primeru zataknemo metodo get, da vedno vržemo RuntimeException. Preostalo vedenje ostaja enako.

@Test (pričakovano = RuntimeException.class) public void testSpyReturnsStubbedValues ​​() vrže izjemo {listSpy.add (nov niz ("dobie")); assertEquals (1, listSpy.size ()); kdaj (listSpy.get (anyInt ())). thenThrow (new RuntimeException ()); listSpy.get (0); } 

V tem primeru ponovno obdržimo jedro vedenja, vendar spremenimo metodo size (), da vrnemo 1 in 5 za vse nadaljnje klice.

public void testSpyReturnsStubbedValues2 () vrže izjemo {int size = 5; when (listSpy.size ()). thenReturn (1, velikost); int mockedListSize = listSpy.size (); assertEquals (1, mockedListSize); mockedListSize = listSpy.size (); assertEquals (5, mockedListSize); mockedListSize = listSpy.size (); assertEquals (5, mockedListSize); } 

To je čudovita čarovnija!

//xunitpatterns.com/Fake%20Object.html

Ponarejeni predmeti so običajno ročno izdelani ali lahki predmeti, ki se uporabljajo samo za testiranje in niso primerni za izdelavo. Dober primer bi bila baza podatkov v pomnilniku ali lažna plast storitve.

Običajno ponujajo veliko več funkcionalnosti kot običajni testni dvojniki in kot taki verjetno niso kandidati za izvedbo z uporabo Mockita. To ne pomeni, da jih ni bilo mogoče zgraditi kot takih, le da se verjetno ne splača izvajati na ta način.

Preizkusite dvojne vzorce

Endo-testiranje: enotno testiranje z lažnimi predmeti

Lažne vloge, ne predmeti

Posmehi niso škrbine

//msdn.microsoft.com/en-us/magazine/cc163358.aspx

To zgodbo "Mocks And Stubs - Understanding Test Doubles With Mockito" je prvotno objavil JavaWorld.

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