Programmēšana

Izspēles un izspēles - izpratne par testa dubultspēlēm ar Mockito

Bieža lieta, ar kuru es sastopos, ir tas, ka komandas, kas izmanto izsmiekla sistēmu, pieņem, ka viņi ņirgājas.

Viņi nezina, ka izspēles ir tikai viens no vairākiem “Test Doubles”, kurus Džerards Meszaros ir klasificējis vietnē xunitpatterns.com.

Ir svarīgi saprast, ka katram testa dubultā tipam ir atšķirīga loma testēšanā. Tādā pašā veidā, kā jums jāapgūst dažādi modeļi vai refaktorēšana, jums jāsaprot katra testa dubultā veida primitīvās lomas. Pēc tam tos var apvienot, lai sasniegtu testēšanas vajadzības.

Es apskatīšu ļoti īsu vēsturi par to, kā šī klasifikācija radās un kā katrs no šiem veidiem atšķiras.

Es to izdarīšu, izmantojot dažus īsus, vienkāršus piemērus Mockito.

Gadiem ilgi cilvēki ir rakstījuši vieglas sistēmas sastāvdaļu versijas, lai palīdzētu testēšanā. Kopumā to sauca par spītēšanu. 2000. gadā rakstā “Endo-Testing: Unit Testing with Mock Objects” tika ieviests izspēles objekta jēdziens. Kopš tā laika Stubus, izspēles un vairākus cita veida testa objektus Meszaros ir klasificējis kā testa dubultniekus.

Uz šo terminoloģiju atsaucās Martin Fowler dokumentā "Mock Are Not Stubs", un tā tiek pieņemta Microsoft kopienā, kā parādīts sadaļā "Pārbaudes dubultspēļu turpināšanas izpēte"

Saite uz katru no šiem svarīgajiem dokumentiem ir parādīta atsauces sadaļā.

Iepriekš redzamajā diagrammā parādīti parasti izmantotie dubultās testa veidi. Šis URL sniedz labu savstarpēju atsauci uz katru no modeļiem un to funkcijām, kā arī uz alternatīvo terminoloģiju.

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

Mockito ir testa spiegu sistēma, un to ir ļoti viegli iemācīties. Mockito ir tas, ka pirms testa netiek definētas cerības uz jebkādiem izspēlētiem objektiem, jo ​​tās dažkārt ir citās izsmiekla sistēmās. Tas noved pie dabiskāka stila (IMHO), sākot ņirgāties.

Turpmāk minētie piemēri ir tikai, lai sniegtu vienkāršu Mockito izmantošanas veidu, lai īstenotu dažāda veida testa dubultspēles.

Vietnē ir daudz lielāks skaits konkrētu piemēru, kā lietot Mockito.

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

Tālāk ir sniegti daži pamata piemēri, izmantojot Mockito, lai parādītu katra testa dubultā lomu, kā definējis Meszaros.

Katram no tiem esmu pievienojis saiti uz galveno definīciju, lai jūs varētu iegūt vairāk piemēru un pilnīgu definīciju.

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

Tas ir vienkāršākais no visiem testa dubultspēlēm. Šis ir objekts, kuram nav ieviešanas, un tas tiek izmantots tikai, lai aizpildītu argumentus par metožu izsaukumiem, kuriem nav nozīmes jūsu pārbaudē.

Piemēram, zemāk esošajā kodā klienta izveidei tiek izmantots daudz koda, kas testam nav svarīgs.

Pārbaude nevarēja mazāk rūpēties par to, kurš klients tiek pievienots, ja vien klientu skaits atgriežas kā viens.

publiskais klients createDummyCustomer () {County county = new County ("Essex"); Pilsētas pilsēta = new City ("Romford", apgabals); Adreses adrese = jaunā adrese ("1234 Bank Street", pilsēta); Klienta klients = jauns klients ("john", "dobie", adrese); atgriešanās klients; } @Test public void addCustomerTest () {Customer dummy = createDummyCustomer (); AddressBook addressBook = jauna adrešu grāmata (); addressBook.addCustomer (manekens); assertEquals (1, addressBook.getNumberOfCustomers ()); } 

Mums faktiski nav vienalga par klienta objekta saturu, bet tas ir nepieciešams. Mēs varam izmēģināt nulles vērtību, taču, ja kods ir pareizs, jūs varētu sagaidīt, ka tiks izmests kaut kāds izņēmums.

@Test (paredzams = Exception.class) public void addNullCustomerTest () {Klienta manekens = null; AddressBook addressBook = jauna adrešu grāmata (); addressBook.addCustomer (manekens); } 

Lai to izvairītos, mēs varam izmantot vienkāršu Mockito manekenu, lai iegūtu vēlamo uzvedību.

@Test public void addCustomerWithDummyTest () {Klienta manekens = izspēles (Customer.class); AddressBook addressBook = jauna adrešu grāmata (); addressBook.addCustomer (manekens); Assert.assertEquals (1, addressBook.getNumberOfCustomers ()); } 

Šis vienkāršais kods rada manekena objektu, kas jānodod zvanam.

Klienta manekens = izspēles (Customer.class);

Neļaujiet sevi apmānīt ar izspēles sintaksi - šeit tiek spēlēta manekena, nevis izspēles loma.

To izceļ testa dubultā loma, nevis sintakse, ko izmanto, lai to izveidotu.

Šī klase darbojas kā vienkāršs klientu klases aizstājējs un padara testu ļoti viegli lasāmu.

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

Testa stumbra uzdevums ir atgriezt kontrolētās vērtības pārbaudāmajam objektam. Tos raksturo kā netiešus testa rezultātus. Cerams, ka piemērs paskaidros, ko tas nozīmē.

Paņemiet šādu kodu

publiskā klase SimplePricingService īsteno PricingService {PricingRepository repository; public SimplePricingService (PricingRepository pricingRepository) {this.repository = pricingRepository; } @Override public Price priceTrade (Tirdzniecības tirdzniecība) {return repository.getPriceForTrade (tirdzniecība); } @ Pārvarēt publisko cenu getTotalPriceForTrades (Kolekcijas darījumi) {Cena kopāCena = jauna Cena (); par (Tirdzniecības tirdzniecība: tirdzniecība) {Cenu tirdzniecībaPrice = repository.getPriceForTrade (tirdzniecība); totalPrice = totalPrice.add (tradePrice); } return totalPrice; } 

SimplePricingService ir viens sadarbības objekts, kas ir darījumu krātuve. Darījumu reģistrs cenu noteikšanas dienestam nodrošina tirdzniecības cenas, izmantojot metodi getPriceForTrade.

Lai mēs varētu pārbaudīt apmācāmo loģiku SimplePricingService, mums ir jākontrolē šie netiešie dati

i., ievadi, kurus mēs nekad neizturējām testā.

Tas parādīts zemāk.

Šajā piemērā mēs nosakām PricingRepository, lai atgrieztu zināmās vērtības, kuras var izmantot, lai pārbaudītu SimpleTradeService biznesa loģiku.

@Test public void testGetHighestPricedTrade () izmet izņēmumu {Cena cena1 = jauna Cena (10); Cenas cena2 = jauna Cena (15); Cenas cena3 = jauna cena (25); PricingRepository pricingRepository = izspēles (PricingRepository.class); kad (pricingRepository.getPriceForTrade (jebkurš (Trade.class))) .thenReturn (cena1, cena2, cena3); Pakalpojums PricingService = jauns SimplePricingService (pricingRepository); Cena augstākā cena = pakalpojums.getHighestPricedTrade (getTrades ()); assertEquals (cena3.getAmount (), augstākā cena.getAmount ()); } 

Sabotētāja piemērs

Ir 2 kopējie testa stumbru varianti: Responder’s un Saboteur's.

Atbildētāja tiek izmantoti, lai pārbaudītu laimīgo ceļu, kā tas bija iepriekšējā piemērā.

Lai pārbaudītu ārkārtas izturēšanos, kā norādīts zemāk, tiek izmantots diversants.

@Test (paredzams = TradeNotFoundException.class) public void testInvalidTrade () izmet izņēmumu {Tirdzniecības tirdzniecība = new FixtureHelper (). GetTrade (); TradeRepository tradeRepository = izspēles (TradeRepository.class); kad (tradeRepository.getTradeById (anyLong ())) .thenThrow (jauns TradeNotFoundException ()); TradingService tradingService = jauns SimpleTradingService (tradeRepository); tradingService.getTradeById (tirdzniecība.getId ()); } 

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

Izspēles objekti tiek izmantoti, lai pārbaudītu objekta uzvedību testa laikā. Ar objekta izturēšanos es domāju, ka, pārbaudot objektu, mēs pārbaudām, vai objektam tiek izmantotas pareizās metodes un ceļi.

Tas ļoti atšķiras no stumbra atbalsta lomas, kas tiek izmantots, lai sniegtu rezultātus neatkarīgi no tā, ko jūs pārbaudāt.

Spraudnī mēs izmantojam metodes atgriešanās vērtības noteikšanas modeli.

kad (klients.getSurname ()). tadReturn (uzvārds); 

Izspēlē mēs pārbaudām objekta uzvedību, izmantojot šādu veidlapu.

pārbaudīt (listMock) .add (s); 

Šeit ir vienkāršs piemērs, kur mēs vēlamies pārbaudīt, vai jauns darījums tiek pareizi auditēts.

Šeit ir galvenais kods.

publiskā klase SimpleTradingService īsteno TradingService {TradeRepository tradeRepository; AuditService auditService; public SimpleTradingService (TradeRepository tradeRepository, AuditService auditService) {this.tradeRepository = tradeRepository; this.auditService = auditService; } public Long LongTrade (Tirdzniecības tirdzniecība) iemet CreateTradeException {Long id = tradeRepository.createTrade (tirdzniecība); auditService.logNewTrade (tirdzniecība); atgriešanās ID; } 

Turpmāk sniegtais tests izveido darījumu krātuves trūkumu un izspēli par AuditService

Pēc tam mēs izsaucam verifikāciju izsmietajā AuditService, lai pārliecinātos, vai TradeService to izsauc

logNewTrade metode pareizi

@Mock TradeRepository tradeRepository; @Mock AuditService auditService; @Test public void testAuditLogEntryMadeForNewTrade () izmet izņēmumu {Tirdzniecības tirdzniecība = jauna tirdzniecība ("Ref 1", "Apraksts 1"); kad (tradeRepository.createTrade (tirdzniecība)). thenReturn (anyLong ()); TradingService tradingService = jauns SimpleTradingService (tradeRepository, auditService); tradingService.createTrade (tirdzniecība); pārbaudīt (auditService) .logNewTrade (tirdzniecība); } 

Šajā rindā tiek pārbaudīts izsmietais AuditService.

pārbaudīt (auditService) .logNewTrade (tirdzniecība);

Šis tests ļauj mums parādīt, ka revīzijas dienests, veidojot darījumu, rīkojas pareizi.

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

Ir vērts ieskatīties iepriekš minētajā saitē, lai precīzi definētu testa spiegu.

Tomēr Mockito es vēlētos to izmantot, lai ļautu jums ietīt reālu objektu un pēc tam pārbaudīt vai modificēt tā uzvedību, lai atbalstītu jūsu testēšanu.

Šis ir piemērs, ja mēs pārbaudījām saraksta standarta darbību. Ņemiet vērā, ka mēs varam gan pārbaudīt, vai tiek izsaukta pievienošanas metode, gan arī apgalvot, ka vienums tika pievienots sarakstam.

@Spy List listSpy = jauns ArrayList (); @Test public void testSpyReturnsRealValues ​​() izmet izņēmumu {String s = "dobie"; listSpy.add (jauna (-as) virkne (-es)); pārbaudīt (listSpy) .add (s); assertEquals (1, listSpy.size ()); } 

Salīdziniet to ar izspēles objekta izmantošanu, kurā var apstiprināt tikai metodes izsaukumu. Tā kā mēs tikai ņirgājamies par saraksta rīcību, tas neieraksta, ka vienums ir pievienots, un atgriež noklusējuma vērtību nulle, kad izsaucam metodi size ().

@Mock List listMock = new ArrayList (); @Test public void testMockReturnsZero () izmet izņēmumu {String s = "dobie"; listMock.add (jauna virkne (-es)); pārbaudīt (listMock) .add (s); assertEquals (0, listMock.size ()); } 

Vēl viena noderīga testSpy iezīme ir spēja atcelt zvanus. Kad tas ir izdarīts, objekts rīkosies kā parasti, līdz tiek izsaukta spītīgā metode.

Šajā piemērā mēs izmantojam get metodi, lai vienmēr izmestu RuntimeException. Pārējā uzvedība paliek nemainīga.

@Test (paredzams = RuntimeException.class) public void testSpyReturnsStubbedValues ​​() izmet izņēmumu {listSpy.add (jauna virkne ("dobie")); assertEquals (1, listSpy.size ()); kad (listSpy.get (anyInt ())). thenThrow (jauns RuntimeException ()); listSpy.get (0); } 

Šajā piemērā mēs atkal saglabājam pamata uzvedību, bet mainām izmēra () metodi, lai sākotnēji atgrieztu 1 un 5 visiem nākamajiem zvaniem.

public void testSpyReturnsStubbedValues2 () throws Exception {int size = 5; kad (listSpy.size ()). thenReturn (1, size); int mockedListSize = listSpy.size (); assertEquals (1, mockedListSize); mockedListSize = listSpy.size (); assertEquals (5, mockedListSize); mockedListSize = listSpy.size (); assertEquals (5, mockedListSize); } 

Šī ir diezgan burvība!

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

Viltoti priekšmeti parasti ir ar rokām izgatavoti vai viegli izstrādājumi, kurus izmanto tikai testēšanai un nav piemēroti ražošanai. Labs piemērs būtu atmiņā ievietota datu bāze vai viltus pakalpojumu slānis.

Tie mēdz nodrošināt daudz lielāku funkcionalitāti nekā standarta testa dubultspēles, un tāpēc tie, iespējams, parasti nav kandidāti ieviešanai, izmantojot Mockito. Tas nenozīmē, ka tos nevarētu konstruēt kā tādus, tikai tas, iespējams, nav tā vērts.

Pārbaudiet dubultos modeļus

Endo-Testing: Vienības pārbaude ar izspēles objektiem

Izspēles lomas, nevis objekti

Izspēles nav Stubs

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

Šo stāstu “Mock And Stubs - Understanding Test Doubles With Mockito” sākotnēji publicēja JavaWorld.

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