mocking private static
Aflați metode private, statice și de vid în Mockito cu exemple:
În această serie de practici Tutoriale despre Mockito , ne-am uitat la diferite tipuri de Mockito Matchers în ultimul tutorial.
În general vorbind, batjocorirea metodelor private și statice intră în categoria batjocoririi neobișnuite.
Dacă apare nevoia de a batjocori metodele / clasele private și statice, aceasta indică un cod slab refactorizat și nu este într-adevăr un cod testabil și este cel mai probabil ca un cod vechi care nu a fost folosit să fie foarte ușor de testat.
Acestea fiind spuse, există încă suport pentru metodele private și statice de batjocură prin câteva cadre de testare unitară, cum ar fi PowerMockito (și nu direct de către Mockito).
Metodele batjocoritoare „void” sunt obișnuite deoarece pot exista metode care în esență nu returnează nimic, cum ar fi actualizarea unui rând de bază de date (considerați-o ca o operațiune PUT a unui punct final Rest API care acceptă o intrare și nu returnează nicio ieșire).
Mockito oferă suport complet pentru metodele de batjocură a golului, pe care le vom vedea cu exemple în acest articol.
cum se inversează ordinea unui tablou în java
Ce veți învăța:
- Powermock - O scurtă introducere
- Metode private batjocoritoare
- Metodele statice batjocoritoare
- Metode de batjocură a vidului
- Sfaturi si trucuri
- Concluzie
- Lectură recomandată
Powermock - O scurtă introducere
Pentru Mockito, nu există suport direct pentru a batjocori metode private și statice. Pentru a testa metode private, va trebui refactorizați codul pentru a schimba accesul la protejat (sau pachet) și va trebui să evitați metodele statice / finale.
Mockito, în opinia mea, nu oferă intenționat suport pentru aceste tipuri de batjocuri, deoarece utilizarea acestor tipuri de construcții de cod sunt mirosuri de cod și cod prost conceput.
Dar există cadre care acceptă batjocura pentru metode private și statice.
Powermock extinde capacitățile altor cadre precum EasyMock și Mockito și oferă capacitatea de a batjocori metode statice și private.
# 1) Cum: Powermock face acest lucru cu ajutorul manipulării codurilor de bytec personalizate pentru a sprijini metodele private și statice de batjocură, clasele finale, constructorii și așa mai departe.
# 2) Pachete acceptate: Powermock oferă 2 API-uri de extensie - una pentru Mockito și una pentru easyMock. De dragul acestui articol, vom scrie exemple cu extensia Mockito pentru power mock.
# 3) Sintaxă :Powermockito are o sintaxă aproape similară cu Mockito, cu excepția unor metode suplimentare pentru batjocorirea metodelor statice și private.
# 4) Configurare Powermockito
Pentru a include biblioteca Mockito în proiectele bazate pe gradle, mai jos sunt bibliotecile care trebuie incluse:
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '1.7.4' testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '1.7.4'
Dependențe similare sunt disponibile și pentru maven.
Powermock-api-mockito2 - Biblioteca trebuie să includă extensii Mockito pentru Powermockito.
Powermock-module-junit4 - Modulul este necesar pentru a include PowerMockRunner (care este un runner personalizat pentru a fi utilizat pentru efectuarea testelor cu PowerMockito).
Un punct important de remarcat aici este că PowerMock nu acceptă testul Junit5. Prin urmare, testele trebuie scrise împotriva Junit4 și testele trebuie executate cu PowerMockRunner.
Pentru a utiliza PowerMockRunner - clasa de test trebuie adnotată cu @RunWith (PowerMockRunner.class)
Acum să discutăm, batjocorind metode private, statice și nule în detaliu!
Metode private batjocoritoare
Batjocorirea metodelor private, care sunt apelate intern dintr-o metodă testată poate fi inevitabilă în anumite momente. Folosind powermockito, acest lucru este posibil, iar verificarea se face folosind o nouă metodă numită „verifyPrivate”
Hai sa luam unExemplu unde metoda testată apelează o metodă privată (care returnează un boolean). Pentru a elimina această metodă pentru a returna adevărat / fals, în funcție de test, trebuie configurat un cod pentru această clasă.
Pentru acest exemplu, clasa supusă testului este creată ca o instanță de spionaj cu batjocură pe câteva invocații de interfață și invocare de metode private.
Puncte importante pentru Mock Private Method:
# 1) Metoda de testare sau clasa de testare trebuie adnotată cu @ PrepareForTest (ClassUnderTest). Această adnotare îi spune lui PowerMockito să pregătească anumite clase pentru testare.
Acestea vor fi în mare parte acele clase care trebuie să fie Bytecode manipulat . De obicei pentru clasele finale, clase care conțin metode private și / sau statice care trebuie să fie batjocorite în timpul testării.
Exemplu:
@PrepareForTest(PriceCalculator.class)
#Două) Pentru a configura stub pe o metodă privată.
Sintaxă - when (instanță falsă sau de spionaj, „privateMethodName”). thenReturn (// return value)
Exemplu:
when (priceCalculatorSpy, 'isCustomerAnonymous').thenReturn(false);
# 3) Pentru a verifica metoda privată.
Sintaxă - verifyPrivate (mockedInstance) .invoke („privateMethodName”)
Exemplu:
verifyPrivate (priceCalculator).invoke('isCustomerAnonymous');
Exemplu complet de testare: Continuând același exemplu din articolele anterioare, unde priceCalculator are unele dependențe batjocorite, cum ar fi itemService, userService etc.
Am creat o nouă metodă numită - calculatePriceWithPrivateMethod, care apelează o metodă privată din aceeași clasă și returnează indiferent dacă clientul este anonim sau nu.
@Test @PrepareForTest(PriceCalculator.class) public void calculatePriceForAnonymous_witStubbedPrivateMethod_returnsCorrectPrice() throws Exception { // Arrange ItemSku item1 = new ItemSku(); item1.setApplicableDiscount(5.00); item1.setPrice(100.00); double expectedPrice = 90.00; // Setting up stubbed responses using mocks when(priceCalculatorSpy, 'isCustomerAnonymous').thenReturn(false); when(mockedItemService.getItemDetails(123)).thenReturn(item1); // Act double actualDiscountedPrice = priceCalculatorSpy.calculatePriceWithPrivateMethod(123); // Assert verifyPrivate(priceCalculator).invoke('isCustomerAnonymous'); assertEquals(expectedPrice, actualDiscountedPrice); }
Metodele statice batjocoritoare
Metodele statice pot fi batjocorite într-un mod similar, așa cum am văzut pentru metodele private.
Când o metodă testată implică utilizarea unei metode statice din aceeași clasă (sau dintr-o altă clasă), va trebui să includem acea clasă în adnotarea prepareForTest înainte de Test (sau pe clasa de test).
Puncte importante ale metodelor statice simulate:
# 1) Metoda de testare sau clasa de testare trebuie adnotată cu @ PrepareForTest (ClassUnderTest). Similar cu metodele / clasele private batjocoritoare, acest lucru este necesar și pentru clasele statice.
#Două) Un pas suplimentar care este necesar pentru metodele statice este - mockStatic (// numele clasei statice)
Exemplu:
mockStatic(DiscountCategoryFinder.class)
# 3) Pentru a configura stub pe o metodă statică, este la fel de bun ca stubbing orice metodă pe orice alte instanțe de interfață / clasă.
De exemplu: Pentru a stub getDiscountCategory () (care returnează o enumerare DiscountCategory cu valori PREMIUM & GENERAL) metoda statică a clasei DiscountCategoryFinder, pur și simplu stub după cum urmează:
when (DiscountCategoryFinder. getDiscountCategory ()).thenReturn(DiscountCategory. PREMIUM );
# 4) Pentru a verifica configurația falsă a metodei finale / statice, se poate utiliza metoda verifyStatic ().
Exemplu:
verifyStatic (DiscountCategoryFinder.class, times (1));
Metode de batjocură a vidului
Să încercăm mai întâi să înțelegem ce fel de cazuri de utilizare ar putea implica metodele de eliminare a nulității:
# 1) Metode de apeluri de exemplu - care trimite o notificare prin e-mail în timpul procesului.
De exemplu :Să presupunem că vă schimbați parola pentru contul dvs. bancar pe internet, după ce schimbarea are succes, veți primi o notificare prin e-mail.
Acest lucru poate fi considerat ca / changePassword ca un apel POST către API-ul băncii care include un apel cu metodă nulă pentru a trimite o notificare prin e-mail către client.
#Două) Un alt exemplu obișnuit de apel metodă nulă este actualizarea cererilor către un DB care iau o intrare și nu returnează nimic.
Metodele de stingere a golului (adică metodele care nu returnează nimic sau altfel aruncă o excepție) pot fi tratate folosind funcțiile doNothing (), doThrow () și doAnswer (), doCallRealMethod () . Necesită configurarea stubului utilizând metodele de mai sus, conform așteptărilor testului.
De asemenea, vă rugăm să rețineți că toate apelurile de metodă nulă sunt în mod implicit batjocorite pentru a face nimic (). Prin urmare, chiar dacă nu se realizează o configurație falsă explicită ANULAȚI apeluri de metodă, comportamentul implicit este încă de a face Nimic ().
Să vedem exemple pentru toate aceste funcții:
Pentru toate exemplele, să presupunem că există o clasă StudentScoreUpdates care are o metodă calculateSumAndStore (). Această metodă calculează suma scorurilor (ca intrare) și apelează a nul metodă updateScores () pe instanța databaseImplementation.
public class StudentScoreUpdates { public IDatabase databaseImpl; public StudentScoreUpdates(IDatabase databaseImpl) { this.databaseImpl = databaseImpl; } public void calculateSumAndStore(String studentId, int() scores) { int total = 0; for(int score : scores) { total = total + score; } // write total to DB databaseImpl.updateScores(studentId, total); } }
Vom scrie teste unitare pentru apelul metodei simulate cu exemplele de mai jos:
# 1) DoNothing () - doNothing () este comportamentul implicit pentru apelurile de metodă void în Mockito, adică chiar dacă verificați un apel pe metoda void (fără a configura în mod explicit un gol pentru a face DoNothing (), verificarea va avea succes)
public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabase); int() scores = {60,70,90}; Mockito.doNothing().when(mockDatabase).updateScores(anyString(), anyInt()); // Act studentScores.calculateSumAndStore('student1', scores); // Assert Mockito.verify(mockDatabase, Mockito.times(1)).updateScores(anyString(), anyInt()); }
Alte utilizări împreună cu doNothing ()
la) Când metoda void este apelată de mai multe ori și doriți să configurați răspunsuri diferite pentru invocații diferite, cum ar fi - doNothing () pentru prima invocație și aruncați o excepție la următoarea invocare.
De exemplu :Configurați o batjocură astfel:
Mockito. doNothing ().doThrow(new RuntimeException()).when(mockDatabase).updateScores( anyString (), anyInt ());
b) Când doriți să capturați argumentele cu care a fost apelată metoda void, ar trebui folosită funcționalitatea ArgumentCaptor din Mockito. Aceasta oferă o verificare suplimentară a argumentelor cu care a fost apelată metoda.
Exemplu cu ArgumentCaptor:
public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabase); int() scores = {60,70,90}; Mockito.doNothing().when(mockDatabase).updateScores(anyString(), anyInt()); ArgumentCaptor studentIdArgument = ArgumentCaptor.forClass(String.class); // Act studentScores.calculateSumAndStore('Student1', scores); // Assert Mockito.verify(mockDatabase, Mockito.times(1)).updateScores(studentIdArgument.capture(), anyInt()); assertEquals('Student1', studentIdArgument.getValue()); }
# 2) doThrow ()- Acest lucru este util atunci când doriți pur și simplu să aruncați o excepție atunci când metoda void este invocată din metoda testată.
De exemplu:
Mockito.doThrow(newRuntimeException()).when(mockDatabase).updateScores ( anyString (), anyInt ());
# 3) doAnswer ()- doAnswer () oferă pur și simplu o interfață pentru a face o anumită logică personalizată.
De exemplu. Modificarea unor valori prin argumentele trecute, returnarea valorilor / datelor personalizate pe care un stub normal nu le-ar fi putut returna în special pentru metodele de anulare.
În scopul demonstrării - am eliminat metoda updateScores () void pentru a returna un „ Răspuns() ”Și tipăriți valoarea unuia dintre argumentele care ar fi trebuit transmise atunci când ar fi trebuit apelată metoda.
Exemplu de cod:
@Test public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabaseImpl); int() scores = {60,70,90}; Mockito.doCallRealMethod().when(mockDatabaseImpl).updateScores(anyString(), anyInt()); doAnswer(invocation -> { Object() args = invocation.getArguments(); Object mock = invocation.getMock(); System.out.println(args(0)); return mock; }).when(mockDatabaseImpl).updateScores(anyString(), anyInt()); // Act studentScores.calculateSumAndStore('Student1', scores); // Assert Mockito.verify(mockDatabaseImpl, Mockito.times(1)).updateScores(anyString(), anyInt()); }
# 4) doCallRealMethod ()- Batjocurile parțiale sunt asemănătoare cu butoanele (unde puteți apela la metode reale pentru unele dintre metode și le puteți tăia pe restul).
Pentru metodele de nulitate, mockito oferă o funcție specială numită doCallRealMethod () care poate fi utilizată atunci când încercați să configurați mock-ul. Ceea ce va face acest lucru este să numim metoda reală a vidului cu argumentele reale.
De exemplu:
Mockito. doCallRealMethod ().when(mockDatabaseImpl).updateScores( anyString (), anyInt ());
Sfaturi si trucuri
# 1) Includerea mai multor clase statice în aceeași metodă / clasă de testare- Folosind PowerMockito dacă este nevoie să batjocoresc mai multe clase Static din Final, atunci numele claselor din @ PrepareForTest adnotarea poate fi menționată ca valoare separată prin virgulă ca o matrice (acceptă în esență o matrice de nume de clase).
Exemplu:
@PrepareForTest({PriceCalculator.class, DiscountCategoryFinder.class})
Așa cum se arată în exemplul de mai sus, presupunem că atât PriceCalculator, cât și DiscountCategoryFinder sunt clase finale care trebuie batjocorite. Ambele pot fi menționate ca o serie de clase în adnotarea PrepareForTest și pot fi introduse în metoda de testare.
# 2) Poziționarea atributului PrepareForTest - Poziționarea acestui atribut este importantă în ceea ce privește tipul de teste care sunt incluse în clasa Test.
diferența dintre testarea fumului și testarea sănătății
Dacă toate testele trebuie să utilizeze aceeași clasă finală, atunci are sens să menționăm acest atribut la nivelul clasei de testare, ceea ce înseamnă pur și simplu că clasa pregătită va fi disponibilă pentru toate metodele de testare. Spre deosebire de aceasta, dacă adnotarea este menționată pe metoda de testare, atunci va fi disponibilă numai pentru testele respective
Concluzie
În acest tutorial, am discutat diverse abordări pentru a batjocori metodele statice, finale și nule.
Deși utilizarea multor metode statice sau finale împiedică testabilitatea, totuși, există suport disponibil pentru testare / batjocură pentru a ajuta la crearea testelor unitare pentru a obține o mai mare încredere în cod / aplicație chiar și pentru codul vechi care, în general, nu este folosit pentru să fie proiectat pentru testabilitate.
Pentru metodele statice și finale, Mockito nu are un suport out of box, dar bibliotecile precum PowerMockito (care moștenesc foarte mult o mulțime de lucruri de la Mockito) oferă un astfel de suport și trebuie să efectueze de fapt manipularea codurilor byt pentru a sprijini aceste caracteristici.
Mockito out of the box acceptă metode de eliminare a golurilor și oferă diverse metode, cum ar fi doNothing, doAnswer, doThrow, doCallRealMethod etc. și poate fi utilizat conform cerințelor testului.
Cele mai frecvente întrebări ale interviului Mockito sunt prezentate în următorul nostru tutorial.
Lectură recomandată
- Tutorial Mockito: Mockito Framework pentru batjocură în testarea unității
- Top 12 Întrebări despre interviul Mockito (Interviul Mocking Framework)
- Static în C ++
- Fire Java cu metode și ciclu de viață
- Crearea de batjocuri și spioni în Mockito cu exemple de cod
- Diferite tipuri de chibrituri furnizate de Mockito
- Metode și tehnici de prevenire a defectelor
- Cum se utilizează metode în SoapUI pentru executarea testelor în bloc - Tutorial SoapUI # 10