mocking private static
Apreneu mètodes de burla privada, estàtica i buida a Mockito amb exemples:
En aquesta sèrie de pràctiques Tutorials sobre Mockito , vam fer una ullada al diferents tipus de Mockito Matchers a l'últim tutorial.
En termes generals, els mètodes de burla privats i estàtics entren en la categoria de burles inusuals.
Si sorgeix la necessitat de burlar-se de mètodes / classes privats i estàtics, indica un codi poc refactoritzat i no és realment un codi comprovable i és probable que algun codi heretat que no s’utilitzés fos molt fàcil de provar per unitats.
Dit això, encara existeix suport per als mètodes estàtics i privats de Mocking mitjançant pocs marcs de proves d’unitats com PowerMockito (i no directament per Mockito).
Els mètodes de burla de 'buit' són habituals, ja que hi pot haver mètodes que bàsicament no retornin res, com ara actualitzar una fila de base de dades (considereu-la com una operació PUT d'un punt final de l'API Rest que accepta una entrada i no retorna cap sortida).
Mockito proporciona suport complet per als mètodes de burla de burles, que veurem amb exemples en aquest article.
millors programes per controlar la temperatura de la CPU
Què aprendreu:
- Powermock: una breu introducció
- Mètodes de burla privats
- Mètodes estàtics burlats
- Mètodes de burla del buit
- Consells i trucs
- Conclusió
- Lectura recomanada
Powermock - Una breu introducció
Per a Mockito, no hi ha suport directe per burlar mètodes privats i estàtics. Per provar mètodes privats, caldrà refactoritzar el codi per canviar l'accés a protegit (o paquet) i haureu d'evitar mètodes estàtics / finals.
Mockito, al meu entendre, intencionalment no proporciona suport per a aquest tipus de simulacions, ja que l'ús d'aquest tipus de construccions de codi són olors de codi i codi mal dissenyat.
Però hi ha marcs que donen suport a la burla de mètodes privats i estàtics.
Powermock amplia les capacitats d'altres marcs com EasyMock i Mockito i proporciona la possibilitat de burlar mètodes estàtics i privats.
# 1) Com: Powermock ho fa amb l'ajut de la manipulació de codis byt personalitzats per tal de donar suport a mètodes estàtics i privats burlats, classes finals, constructors, etc.
# 2) Paquets compatibles: Powermock proporciona dues API d’extensió: una per a Mockito i una per a easyMock. En nom d’aquest article, escriurem exemples amb l’extensió Mockito per a la simulació de potència.
# 3) Sintaxi :Powermockito té una sintaxi gairebé similar a Mockito, excepte alguns mètodes addicionals per burlar-se de mètodes estàtics i privats.
# 4) Configuració de Powermockito
Per incloure la biblioteca Mockito en projectes basats en gradle, a continuació es mostren les biblioteques que s’han d’incloure:
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '1.7.4' testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '1.7.4'
També hi ha dependències similars disponibles per a maven.
Powermock-api-mockito2 - Cal que la biblioteca inclogui extensions Mockito per a Powermockito.
Powermock-module-junit4 - Cal que el mòdul inclogui PowerMockRunner (que és un corredor personalitzat que s’utilitzarà per executar proves amb PowerMockito).
Un punt important a destacar aquí és que PowerMock no admet el corredor de proves Junit5. Per tant, les proves s’han d’escriure contra Junit4 i les proves s’han d’executar amb PowerMockRunner.
Per utilitzar PowerMockRunner: cal anotar la classe de prova @RunWith (PowerMockRunner.class)
Ara discutim, burlant-nos detalladament de mètodes privats, estàtics i nuls.
Mètodes de burla privats
La burla de mètodes privats, que es diuen internament des d’un mètode sotmès a prova, pot ser inevitable en determinats moments. Amb powermockito, això és possible i la verificació es fa mitjançant un mètode nou anomenat 'verifyPrivate'
Prenem unExemple on el mètode en prova crida un mètode privat (que retorna un booleà). Per tal de reduir aquest mètode per tornar cert / fals en funció de la prova, cal configurar-ne un en aquesta classe.
Per a aquest exemple, la classe que es prova es crea com una instància espia amb burles en poques invocacions d'interfície i invocació de mètodes privats.
Punts importants de Mock Private Method:
# 1) Cal anotar el mètode de prova o la classe de prova amb @ PrepareForTest (ClassUnderTest). Aquesta anotació indica a powerMockito que prepari certes classes per provar-les.
Aquestes seran principalment aquelles classes que cal fer-ho Bytecode manipulat . Normalment per a classes finals, classes que contenen mètodes privats i / o estàtics que cal burlar durant la prova.
Exemple:
@PrepareForTest(PriceCalculator.class)
# 2) Per configurar un mètode privat.
Sintaxi - quan (instància simulada o espia, 'privateMethodName'). thenReturn (// valor de devolució)
Exemple:
when (priceCalculatorSpy, 'isCustomerAnonymous').thenReturn(false);
# 3) Per verificar el mètode privat obstaculitzat.
Sintaxi - verifyPrivate (mockedInstance) .invoke ('privateMethodName')
Exemple:
verifyPrivate (priceCalculator).invoke('isCustomerAnonymous');
Mostra de prova completa: Continuant amb el mateix exemple dels articles anteriors, on priceCalculator té algunes dependències burlades com itemService, userService, etc.
Hem creat un nou mètode anomenat - calculatePriceWithPrivateMethod, que crida a un mètode privat dins de la mateixa classe i torna si el client és anònim o no.
@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); }
Mètodes estàtics burlats
Els mètodes estàtics es poden burlar d'una manera similar a la que hem vist per als mètodes privats.
Quan un mètode que es prova comprèn l’ús d’un mètode estàtic de la mateixa classe (o d’una classe diferent), haurem d’incloure aquesta classe a l’anotació prepareForTest abans de la prova (o a la classe de prova).
Punts importants dels mètodes estàtics simulats:
# 1) Cal anotar el mètode de prova o la classe de prova amb @ PrepareForTest (ClassUnderTest). De manera similar a la burla de mètodes / classes privats, això també es requereix per a les classes estàtiques.
# 2) Un pas addicional que es requereix per als mètodes estàtics és: mockStatic (// nom de la classe estàtica)
Exemple:
mockStatic(DiscountCategoryFinder.class)
# 3) Per configurar stub en un mètode estàtic, és tan bo com eliminar qualsevol mètode en qualsevol altra instància de simulació d'interfície / classe.
Per exemple: Per restablir getDiscountCategory () (que retorna un enum DiscountCategory amb valors PREMIUM & GENERAL) mètode estàtic de la classe DiscountCategoryFinder, simplement restringiu el següent:
when (DiscountCategoryFinder. getDiscountCategory ()).thenReturn(DiscountCategory. PREMIUM );
# 4) Per verificar la configuració simulada al mètode final / estàtic, es pot utilitzar el mètode verifyStatic ().
Exemple:
verifyStatic (DiscountCategoryFinder.class, times (1));
Mètodes de burla del buit
Intentem primer comprendre quin tipus de casos d’ús poden implicar la reducció dels mètodes de nul·litat:
# 1) Mètodes de trucades per exemple: envia una notificació per correu electrònic durant el procés.
Per exemple :Suposem que canvieu la contrasenya del vostre compte bancari per Internet, un cop el canvi tingui èxit, rebreu una notificació per correu electrònic.
Això es pot considerar com / changePassword com una trucada POST a l'API del banc que inclou una trucada de mètode nul per enviar una notificació per correu electrònic al client.
# 2) Un altre exemple habitual de la trucada al mètode void són les sol·licituds actualitzades a una base de dades que prenen algunes aportacions i no retornen res.
Es poden gestionar els mètodes de buidat (és a dir, els mètodes que no retornen res o que generen una excepció) funcions doNothing (), doThrow () i doAnswer (), doCallRealMethod () . Requereix la configuració del taló mitjançant els mètodes anteriors segons les expectatives de la prova.
Tingueu en compte, a més, que totes les trucades del mètode buit es burlen per defecte de doNothing (). Per tant, fins i tot si no es fa una configuració de simulació explícita BUIT de mètode, el comportament per defecte encara és doNothing ().
Vegem exemples de totes aquestes funcions:
Per a tots els exemples, suposem, que hi ha una classe StudentScoreUpdates que té un mètode calculateSumAndStore (). Aquest mètode calcula la suma de puntuacions (com a entrada) i crida a buit mètode updateScores () a la instància 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); } }
Escrivirem proves unitàries per a la trucada del mètode simulat amb els exemples següents:
# 1) fer res () - doNothing () és el comportament predeterminat per a les trucades al mètode void a Mockito, és a dir, fins i tot si verifiqueu una trucada al mètode void (sense configurar explícitament un buit per fer DoNothing (), la verificació continuarà tenint èxit)
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()); }
Altres usos juntament amb doNothing ()
a) Quan es crida el mètode void diverses vegades i voleu configurar respostes diferents per a diferents invocacions, com ara - doNothing () per a la primera invocació i llançar una excepció a la següent invocació.
Per exemple :Configureu una simulació així:
Mockito. doNothing ().doThrow(new RuntimeException()).when(mockDatabase).updateScores( anyString (), anyInt ());
b) Quan vulgueu capturar els arguments amb els quals s'ha cridat el mètode void, s'hauria d'utilitzar la funcionalitat ArgumentCaptor a Mockito. Això proporciona una verificació addicional dels arguments amb els quals es va anomenar el mètode.
Exemple amb 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 ()- Això és útil quan simplement voleu llançar una excepció quan s'invoca el mètode void des del mètode que es prova.
Per exemple:
Mockito.doThrow(newRuntimeException()).when(mockDatabase).updateScores ( anyString (), anyInt ());
# 3) doAnswer ()- doAnswer () simplement proporciona una interfície per fer una lògica personalitzada.
quina és la vostra clau de seguretat de xarxa
Per exemple. Modificant algun valor a través dels arguments passats, retornant dades / valors personalitzats que un registre normal no hauria pogut retornar, especialment per als mètodes buits.
A efectes de demostració, he eliminat el mètode updateScores () void per tornar un ' respondre () ”I imprimiu el valor d’un dels arguments que s’haurien d’haver passat quan s’hauria d’haver cridat al mètode.
Exemple de codi:
@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 ()- Els simulacres parcials són similars als talons (on podeu anomenar mètodes reals per a alguns dels mètodes i eliminar la resta).
Per als mètodes buits, mockito proporciona una funció especial anomenada doCallRealMethod () que es pot utilitzar quan intenteu configurar la simulació. El que farà això és anomenar el mètode real buit amb els arguments reals.
Per exemple:
Mockito. doCallRealMethod ().when(mockDatabaseImpl).updateScores( anyString (), anyInt ());
Consells i trucs
# 1) Incloure diverses classes estàtiques al mateix mètode / classe de prova- Utilitzant PowerMockito si hi ha la necessitat de burlar-se de diverses classes estàtiques de finals, llavors els noms de les classes a @ PrepareForTest L'anotació es pot esmentar com un valor separat per comes com a matriu (essencialment accepta una matriu dels noms de classe).
Exemple:
@PrepareForTest({PriceCalculator.class, DiscountCategoryFinder.class})
Com es mostra a l’exemple anterior, suposem que PriceCalculator i DiscountCategoryFinder són classes finals que cal burlar. Tots dos es poden esmentar com una matriu de classes a l’anotació PrepareForTest i es poden incloure al mètode de prova.
# 2) Posicionament de l'atribut PrepareForTest - El posicionament d’aquest atribut és important pel que fa al tipus de proves que s’inclouen a la classe Test.
Si totes les proves necessiten utilitzar la mateixa classe final, és lògic esmentar aquest atribut a nivell de classe de prova, cosa que significa simplement que la classe preparada estarà disponible per a tots els mètodes de prova. A diferència d’això, si l’anotació s’esmenta al mètode de prova, només estarà disponible per a les proves concretes
Conclusió
En aquest tutorial, hem discutit diversos enfocaments per burlar mètodes estàtics, finals i buits.
Tot i que l’ús de molts mètodes estàtics o finals dificulta la testabilitat i, tot i així, hi ha suport disponible per fer proves / burles per ajudar a crear proves unitàries per tal d’aconseguir una major confiança en el codi / aplicació, fins i tot per al codi heretat que generalment no s’utilitza per estar dissenyat per a la seva prova
Per als mètodes estàtics i finals, Mockito no disposa de suport pròpiament dit, però biblioteques com PowerMockito (que hereten moltíssimes coses de Mockito) ofereixen aquest suport i ha de realitzar una manipulació de codis byt per tal de donar suport a aquestes funcions.
Mockito fora de la caixa admet mètodes de buit i proporciona diversos mètodes com doNothing, doAnswer, doThrow, doCallRealMethod, etc., i es pot utilitzar segons el requisit de la prova.
Les preguntes més freqüents sobre les entrevistes a Mockito es detallen al nostre següent tutorial.
Lectura recomanada
- Tutorial de Mockito: marc Mockito per burlar-se de les proves unitàries
- Top 12 de les preguntes sobre l'entrevista de Mockito (entrevista de Mocking Framework)
- Estàtic a C ++
- Fils de Java amb mètodes i cicle de vida
- Creació de simulacres i espies a Mockito amb exemples de codi
- Diferents tipus de coincidències proporcionats per Mockito
- Mètodes i tècniques de prevenció de defectes
- Com s'utilitzen mètodes a SoapUI per a l'execució de proves massives: tutorial SoapUI núm. 10