creating mocks spies mockito with code examples
Vadnica za Mockito Spy and Mocks:
V tem Serija vadnic Mockito , prejšnja vadnica nam je dala Uvod v Mockito Framework . V tej vadnici bomo spoznali koncept Mocks and Spies v Mockitu.
Kaj so posmehljivci in vohuni?
Mocki in vohuni so tipi testnih dvojic, ki so v pomoč pri pisanju enotnih testov.
Posmehi so popolna zamenjava odvisnosti in jih je mogoče programirati za vrnitev določenega izhoda vsakič, ko se pokliče metoda v ponaredku. Mockito nudi privzeto izvedbo za vse metode posmeha.
Kaj se boste naučili:
- Kaj so vohuni?
- Ustvarjanje posmehov
- Ustvarjanje vohunov
- Kako vbrizgati posmehljive odvisnosti za preizkušeni razred / predmet?
- Nasveti in triki
- Primeri kode - Vohuni in posmeh
- Izvorna koda
- Priporočeno branje
Kaj so vohuni?
Vohuni so v bistvu ovojnica resničnega primera zasmehovane odvisnosti. To pomeni, da zahteva nov primerek predmeta ali odvisnosti, nato pa nad njim doda ovoj posmehanega predmeta. Vohuni privzeto pokličejo realne metode predmeta, razen če so ogrožene.
Vohuni zagotavljajo določene dodatne moči, na primer, kateri argumenti so bili posredovani klicu metode, ali je bila prava metoda sploh poklicana itd
Na kratko, za vohune:
- Potreben je dejanski primerek predmeta.
- Vohuni omogočajo fleksibilnost nekaterih (ali vseh) metod vohunjenega predmeta. Takrat je vohun v bistvu poklican ali napoten na delno zasmehovan ali zakrknjen predmet.
- Interakcije, ki se pokličejo na vohunjenem objektu, lahko spremljamo za preverjanje.
Na splošno se vohuni ne uporabljajo zelo pogosto, vendar so lahko v pomoč pri enostavnem testiranju starejših aplikacij, kjer odvisnosti ni mogoče v celoti posmehovati.
V celotnem opisu Mock and Spy se sklicujemo na izmišljeni razred / objekt, imenovan ‘DiscountCalculator’, ki ga želimo posmehovati / vohuniti.
Ima nekaj metod, kot je prikazano spodaj:
izračunaj popust - Izračuna znižano ceno določenega izdelka.
getDiscountLimit - Pridobi zgornjo mejo popusta za izdelek.
Ustvarjanje posmehov
# 1) Lažno ustvarjanje s kodo
Mockito ponuja več preobremenjenih različic Mockita. Mocks metoda in omogoča ustvarjanje posmehov za odvisnosti.
Sintaksa:
Mockito.mock(Class classToMock)
Primer:
Recimo, da je ime razreda DiscountCalculator, da ustvarite lažno kodo:
DiscountCalculator mockedDiscountCalculator = Mockito.mock(DiscountCalculator.class)
Pomembno je omeniti, da Mock lahko ustvarite tako za vmesnik kot za konkreten razred.
Ko se predmet posmehuje, razen če vse metode privzeto vrnejo nič .
DiscountCalculator mockDiscountCalculator = Mockito.mock(DiscountCalculator.class);
# 2) Lažno ustvarjanje z opombami
Namesto posmehovanja z uporabo statične metode 'mock' iz knjižnice Mockito ponuja tudi okrajšani način ustvarjanja posmehov z uporabo pripisa '@Mock'.
Največja prednost tega pristopa je, da je preprost in omogoča združitev deklaracije in v bistvu inicializacije. Preizkusi so tudi bolj berljivi in se izogiba ponavljajoči se inicializaciji posmehov, kadar se isti posnetek uporablja na več mestih.
Da bi zagotovili Mock inicializacijo s tem pristopom, je bilo treba za preizkušeni razred poklicati „MockitoAnnotations.initMocks (this)“. To je idealen kandidat za vključitev metode 'beforeEach' iz Junita, ki zagotavlja, da se posmehi inicializirajo vsakič, ko se iz tega razreda izvede test.
Sintaksa:
@Mock private transient DiscountCalculator mockedDiscountCalculator;
Ustvarjanje vohunov
Podobno kot Mocks lahko tudi Vohune ustvarjamo na dva načina:
# 1) Ustvarjanje vohuna s kodo
Mockito.spy je statična metoda, ki se uporablja za ustvarjanje 'vohunskega' predmeta / ovoja okoli primerka pravega predmeta.
Sintaksa:
najboljša vohunska programska oprema za android mobilne telefone
private transient ItemService itemService = new ItemServiceImpl() private transient ItemService spiedItemService = Mockito.spy(itemService);
# 2) Ustvarjanje vohunov z opombami
Podobno kot Mock lahko tudi Vohune ustvarjamo s pripisom @Spy.
Tudi za inicializacijo vohuna morate zagotoviti, da se MockitoAnnotations.initMocks (ta) pokliče, preden se vohuna uporabi v dejanskem testu, da se vohun inicializira.
Sintaksa:
@Spy private transient ItemService spiedItemService = new ItemServiceImpl();
Kako vbrizgati posmehljive odvisnosti za preizkušeni razred / predmet?
Ko želimo ustvariti lažni objekt preizkušenega razreda z drugimi posmehljivimi odvisnostmi, lahko uporabimo pripis @InjectMocks.
To v bistvu naredi, da se vsi predmeti, označeni s pripisi @Mock (ali @Spy), vbrizgajo kot izvajalec ali vbrizgavanje lastnosti v razred Objekt in nato lahko interakcije preverijo na končnem Mocked objektu.
Še enkrat, odveč je omenjati, da je @InjectMocks okrajšava za ustvarjanje novega predmeta predmeta in ponuja posmehljive predmete odvisnosti.
Razumimo to s primerom:
Recimo, da obstaja razred PriceCalculator, ki ima DiscountCalculator in UserService kot odvisnosti, ki se vbrizgata preko polji Constructor ali Property.
Torej, da bi ustvarili Mocked izvedbo za razred kalkulatorja cen, lahko uporabimo 2 pristopa:
# 1) Ustvari nov primerek PriceCalculatorja in vbrizgajte posmehljive odvisnosti
@Mock private transient DiscountCalculator mockedDiscountCalculator; @Mock private transient UserService userService; @Mock private transient ItemService mockedItemService; private transient PriceCalculator priceCalculator; @BeforeEach public void beforeEach() { MockitoAnnotations.initMocks(this); priceCalculator = new PriceCalculator(mockedDiscountCalculator, userService, mockedItemService); }
# 2) Ustvari posmehljivi primerek PriceCalculatorja in vbrizga odvisnosti s pripisom @InjectMocks
@Mock private transient DiscountCalculator mockedDiscountCalculator; @Mock private transient UserService userService; @Mock private transient ItemService mockedItemService; @InjectMocks private transient PriceCalculator priceCalculator; @BeforeEach public void beforeEach() { MockitoAnnotations.initMocks(this);
Pripis InjectMocks dejansko poskuša vbrizgati zasmehane odvisnosti z enim od spodnjih pristopov:
- Vbrizgavanje na osnovi konstruktorja - Uporablja konstruktor za preizkušeni razred.
- Setter Metode temeljijo - Ko konstruktorja ni, poskuša Mockito vbrizgati s pomočjo nastaviteljev lastnosti.
- Na terenu - Če zgornja 2 nista na voljo, poskuša neposredno vbrizgati prek polj.
Nasveti in triki
# 1) Nastavitev različnih klicev za različne klice iste metode:
Ko je v preskušani metodi večkrat poklicana metoda stubbed (ali je metoda stubbed v zanki in želite vsakič vrniti drugačen izhod), lahko nastavite Mock, da vsakič vrne drugačen odziv.
Na primer: Recimo, da želite ItemService če želite vrniti drugačen izdelek za 3 zaporedne klice in imate v svoji metodi v preskusnih postavkah postavke kot Element1, Element2 in Artikel3, nato pa jih lahko preprosto vrnete za 3 zaporedne klice z uporabo spodnje kode:
@Test public void calculatePrice_withCorrectInput_returnsValidResult() { // Arrange ItemSku item1 = new ItemSku(); ItemSku item2 = new ItemSku(); ItemSku item3 = new ItemSku(); // Setup Mocks when(mockedItemService.getItemDetails(anyInt())).thenReturn(item1, item2, item3); // Assert //TODO - add assert statements }
#two) Metanje izjeme skozi posmeh: To je zelo pogost scenarij, ko želite preizkusiti / preveriti navzdol / odvisnost, ki vrže izjemo, in preveriti vedenje preizkušanega sistema. Vendar, da bi Mock vrgel izjemo, boste morali nastaviti škrbino s funkcijo thenThrow.
@Test public void calculatePrice_withInCorrectInput_throwsException() { // Arrange ItemSku item1 = new ItemSku(); // Setup Mocks when(mockedItemService.getItemDetails(anyInt())).thenThrow(new ItemServiceException(anyString())); // Assert //TODO - add assert statements }
Za tekme, kot sta anyInt () in anyString (), se ne ustrašite, saj bodo zajete v prihodnjih člankih. V bistvu pa vam omogočajo samo prožnost pri podajanju vrednosti Integer in String brez posebnih argumentov funkcije.
Primeri kode - Vohuni in posmeh
Kot smo že omenili, sta oba Vohuna in Mocks vrsta testnih dvojic in imata svoje običaje.
Medtem ko so vohuni koristni za preizkušanje starejših aplikacij (in kjer posmehi niso možni), pa za vse druge lepo napisane preizkusne metode / razrede, posmehi zadostujejo za večino potreb po testiranju enote.
Za isti primer: Naj napišemo test z uporabo Mocks for PriceCalculator -> izračunaj metodoPrice (metoda izračuna ceno artiklaCena manj od veljavnih popustov)
Razred PriceCalculator in preskušana metoda izračunataCena izgleda, kot je prikazano spodaj:
public class PriceCalculator { public DiscountCalculator discountCalculator; public UserService userService; public ItemService itemService; public PriceCalculator(DiscountCalculator discountCalculator, UserService userService, ItemService itemService) { this.discountCalculator = discountCalculator; this.userService = userService; this.itemService = itemService; } public double calculatePrice(int itemSkuCode, int customerAccountId) { double price = 0; // get Item details ItemSku sku = itemService.getItemDetails(itemSkuCode); // get User and calculate price CustomerProfile customerProfile = userService.getUser(customerAccountId); double basePrice = sku.getPrice(); price = basePrice - (basePrice* (sku.getApplicableDiscount() + customerProfile.getExtraLoyaltyDiscountPercentage())/100); return price; } }
Zdaj napišimo pozitiven test za to metodo.
Upoštevali bomo storitev userService in storitve, kot je navedeno spodaj:
- UserService bo vedno vrnil CustomerProfile z loyaltyDiscountPercentage, nastavljenim na 2.
- ItemService bo vedno vrnil izdelek z osnovno ceno 100 in veljavnim popustom 5.
- Z zgornjimi vrednostmi znaša pričakovana cena, ki jo vrne preskušana metoda, 93 $.
Tu je koda za test:
@Test public void calculatePrice_withCorrectInput_returnsExpectedPrice() { // Arrange ItemSku item1 = new ItemSku(); item1.setApplicableDiscount(5.00); item1.setPrice(100.00); CustomerProfile customerProfile = new CustomerProfile(); customerProfile.setExtraLoyaltyDiscountPercentage(2.00); double expectedPrice = 93.00; // Setting up stubbed responses using mocks when(mockedItemService.getItemDetails(anyInt())).thenReturn(item1); when(mockedUserService.getUser(anyInt())).thenReturn(customerProfile); // Act double actualPrice = priceCalculator.calculatePrice(123,5432); // Assert assertEquals(expectedPrice, actualPrice); }
Kot lahko vidite, v zgornjem preizkusu - trdimo, da je dejanska cena, ki jo vrne metoda, enaka pričakovani ceni, to je 93,00.
Zdaj pa napišimo test s pomočjo Vohuna.
Špijunirali bomo ItemService in kodirali bomo izvedbo ItemService tako, da bo vedno vrnil element z basePrice 200 in veljavnim popustom 10,00% (preostali del lažne nastavitve ostane enak), kadar koli je poklican s skuCode 2367.
krožno povezan seznam v c ++
@InjectMocks private PriceCalculator priceCalculator; @Mock private DiscountCalculator mockedDiscountCalculator; @Mock private UserService mockedUserService; @Spy private ItemService mockedItemService = new ItemServiceImpl(); @BeforeEach public void beforeEach() { MockitoAnnotations.initMocks(this); } @Test public void calculatePrice_withCorrectInputRealMethodCall_returnsExpectedPrice() { // Arrange CustomerProfile customerProfile = new CustomerProfile(); customerProfile.setExtraLoyaltyDiscountPercentage(2.00); double expectedPrice = 176.00; // Setting up stubbed responses using mocks when(mockedUserService.getUser(anyInt())).thenReturn(customerProfile); // Act double actualPrice = priceCalculator.calculatePrice(2367,5432); // Assert assertEquals(expectedPrice, actualPrice);
Zdaj pa poglejmo Primer izjeme, ki jo vrže ItemService, saj je bila razpoložljiva količina artikla 0. Nastavili bomo posnemanje, da vržemo izjemo.
@InjectMocks private PriceCalculator priceCalculator; @Mock private DiscountCalculator mockedDiscountCalculator; @Mock private UserService mockedUserService; @Mock private ItemService mockedItemService = new ItemServiceImpl(); @BeforeEach public void beforeEach() { MockitoAnnotations.initMocks(this); } @Test public void calculatePrice_whenItemNotAvailable_throwsException() { // Arrange CustomerProfile customerProfile = new CustomerProfile(); customerProfile.setExtraLoyaltyDiscountPercentage(2.00); double expectedPrice = 176.00; // Setting up stubbed responses using mocks when(mockedUserService.getUser(anyInt())).thenReturn(customerProfile); when(mockedItemService.getItemDetails(anyInt())).thenThrow(new ItemServiceException(anyString())); // Act & Assert assertThrows(ItemServiceException.class, () -> priceCalculator.calculatePrice(123, 234)); }
Z zgornjimi primeri sem poskušal razložiti koncept Mocks & Spies in kako jih je mogoče kombinirati, da ustvarijo učinkovite in uporabne enote.
Obstaja lahko več kombinacij teh tehnik, da dobite nabor testov, ki povečajo pokritost preskušane metode in s tem zagotovijo veliko stopnjo zaupanja v kodo in naredijo kodo bolj odporno na regresijske napake.
Izvorna koda
Vmesniki
DiscountCalculator
public interface DiscountCalculator { double calculateDiscount(ItemSku itemSku, double markedPrice); void calculateProfitability(ItemSku itemSku, CustomerProfile customerProfile); }
ItemService
public interface ItemService { ItemSku getItemDetails(int skuCode) throws ItemServiceException; }
UserService
public interface UserService { void addUser(CustomerProfile customerProfile); void deleteUser(CustomerProfile customerProfile); CustomerProfile getUser(int customerAccountId); }
Izvedbe vmesnikov
DiscountCalculatorImpl
public class DiscountCalculatorImpl implements DiscountCalculator { @Override public double calculateDiscount(ItemSku itemSku, double markedPrice) { return 0; } @Override public void calculateProfitability(ItemSku itemSku, CustomerProfile customerProfile) { } }
ItemServiceImpl
public class DiscountCalculatorImpl implements DiscountCalculator { @Override public double calculateDiscount(ItemSku itemSku, double markedPrice) { return 0; } @Override public void calculateProfitability(ItemSku itemSku, CustomerProfile customerProfile) { } }
Modeli
Profil stranke
public class CustomerProfile { private String customerName; private String loyaltyTier; private String customerAddress; private String accountId; private double extraLoyaltyDiscountPercentage; public double getExtraLoyaltyDiscountPercentage() { return extraLoyaltyDiscountPercentage; } public void setExtraLoyaltyDiscountPercentage(double extraLoyaltyDiscountPercentage) { this.extraLoyaltyDiscountPercentage = extraLoyaltyDiscountPercentage; } public String getAccountId() { return accountId; } public void setAccountId(String accountId) { this.accountId = accountId; } public String getCustomerName() { return customerName; } public void setCustomerName(String customerName) { this.customerName = customerName; } public String getLoyaltyTier() { return loyaltyTier; } public void setLoyaltyTier(String loyaltyTier) { this.loyaltyTier = loyaltyTier; } public String getCustomerAddress() { return customerAddress; } public void setCustomerAddress(String customerAddress) { this.customerAddress = customerAddress; } }
ItemSku
public class ItemSku { private int skuCode; private double price; private double maxDiscount; private double margin; private int totalQuantity; private double applicableDiscount; public double getApplicableDiscount() { return applicableDiscount; } public void setApplicableDiscount(double applicableDiscount) { this.applicableDiscount = applicableDiscount; } public int getTotalQuantity() { return totalQuantity; } public void setTotalQuantity(int totalQuantity) { this.totalQuantity = totalQuantity; } public int getSkuCode() { return skuCode; } public void setSkuCode(int skuCode) { this.skuCode = skuCode; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public double getMaxDiscount() { return maxDiscount; } public void setMaxDiscount(double maxDiscount) { this.maxDiscount = maxDiscount; } public double getMargin() { return margin; } public void setMargin(double margin) { this.margin = margin; } }
Preizkušeni razred - kalkulator cen
public class PriceCalculator { public DiscountCalculator discountCalculator; public UserService userService; public ItemService itemService; public PriceCalculator(DiscountCalculator discountCalculator, UserService userService, ItemService itemService){ this.discountCalculator = discountCalculator; this.userService = userService; this.itemService = itemService; } public double calculatePrice(int itemSkuCode, int customerAccountId) { double price = 0; // get Item details ItemSku sku = itemService.getItemDetails(itemSkuCode); // get User and calculate price CustomerProfile customerProfile = userService.getUser(customerAccountId); double basePrice = sku.getPrice(); price = basePrice - (basePrice* (sku.getApplicableDiscount() + customerProfile.getExtraLoyaltyDiscountPercentage())/100); return price; } }
Preizkusi enot - PriceCalculatorUnitTests
public class PriceCalculatorUnitTests { @InjectMocks private PriceCalculator priceCalculator; @Mock private DiscountCalculator mockedDiscountCalculator; @Mock private UserService mockedUserService; @Mock private ItemService mockedItemService; @BeforeEach public void beforeEach() { MockitoAnnotations.initMocks(this); } @Test public void calculatePrice_withCorrectInput_returnsExpectedPrice() { // Arrange ItemSku item1 = new ItemSku(); item1.setApplicableDiscount(5.00); item1.setPrice(100.00); CustomerProfile customerProfile = new CustomerProfile(); customerProfile.setExtraLoyaltyDiscountPercentage(2.00); double expectedPrice = 93.00; // Setting up stubbed responses using mocks when(mockedItemService.getItemDetails(anyInt())).thenReturn(item1); when(mockedUserService.getUser(anyInt())).thenReturn(customerProfile); // Act double actualPrice = priceCalculator.calculatePrice(123,5432); // Assert assertEquals(expectedPrice, actualPrice); } @Test @Disabled // to enable this change the ItemService MOCK to SPY public void calculatePrice_withCorrectInputRealMethodCall_returnsExpectedPrice() { // Arrange CustomerProfile customerProfile = new CustomerProfile(); customerProfile.setExtraLoyaltyDiscountPercentage(2.00); double expectedPrice = 176.00; // Setting up stubbed responses using mocks when(mockedUserService.getUser(anyInt())).thenReturn(customerProfile); // Act double actualPrice = priceCalculator.calculatePrice(2367,5432); // Assert assertEquals(expectedPrice, actualPrice); } @Test public void calculatePrice_whenItemNotAvailable_throwsException() { // Arrange CustomerProfile customerProfile = new CustomerProfile(); customerProfile.setExtraLoyaltyDiscountPercentage(2.00); double expectedPrice = 176.00; // Setting up stubbed responses using mocks when(mockedUserService.getUser(anyInt())).thenReturn(customerProfile); when(mockedItemService.getItemDetails(anyInt())).thenThrow(new ItemServiceException(anyString())); // Act & Assert assertThrows(ItemServiceException.class, () -> priceCalculator.calculatePrice(123, 234)); } }
Različne vrste ujemanj, ki jih ponuja Mockito, so razložene v naši prihajajoči vadnici.
PREV Vadnica | NASLEDNJA Vadnica
Priporočeno branje
- Različne vrste ujemanj, ki jih ponuja Mockito
- Vadnica za Mockito: Mockito Framework za posmeh pri preskušanju enot
- Ustvarjanje testov epoh z uporabo epochs Studio za Eclipse
- Vadnica Python DateTime s primeri
- Izreži ukaz v Unixu s primeri
- Sintaksa ukaza Unix Cat, možnosti s primeri
- Uporaba kazalca v MongoDB s primeri
- Ls ukaz v Unixu s primeri