spock mocking stubbing
Burleta, obstrucció i espionatge amb Spock:
Proves parametritzades a Spock Framework s'explicava amb detall en això Sèrie de tutorials de formació a Spock .
compilador c ++ per a eclipsi
El burlatge i el traçat són un dels elements bàsics més importants de les extenses proves d’unitat. El suport per burlar-se i reduir-se és com la cirera del pastís per a un marc.
Per a marcs existents com JUnit, JBehave, etc., el suport per a mock i stubs no surt de la caixa, per tant, requereix que un desenvolupador utilitzi biblioteques de tercers com Mockito, PowerMock, EasyMock, etc. per utilitzar-los a la proves d’unitat.
Per comprendre els simulacres i els rostres i els seus casos d’ús, podeu fer una ullada a la nostra sèrie de Mockito tutorial .
En aquest tutorial, obtindrem més informació sobre les funcions incorporades de Mocking and Stubbing integrades a la pròpia biblioteca Spock, que al seu torn permetrien utilitzar la sintaxi Groovy més fàcil i, per tant, reduir la necessitat d'afegir / incloure qualsevol altrardbiblioteques de festes.
Sempre podeu incloure altres marcs burlats a les proves, ja que tot el codi Java vàlid també és un codi Groovy vàlid.
Què aprendreu:
- Sol·licitud en prova
- Burleta a Spock
- Acoblament a Spock
- Espionatge a Spock
- Conclusió
- Codi font de l'aplicació
- Lectura recomanada
Sol·licitud en prova
Definim en primer lloc una mostra d’aplicació Java, que provarem utilitzant mock i stub en el marc Spock.
Treballarem en una aplicació StudentGradeCalculator que obtingui la puntuació total d’una base de dades abstracta per a una identificació d’estudiant determinada i que tingui una lògica senzilla d’assignació de notes en funció del valor de la puntuació total. Utilitzarem una interfície de base de dades que té pocs mètodes per obtenir i actualitzar les puntuacions i qualificacions dels estudiants.
El codi de l'aplicació estarà disponible a l'última secció d'aquest tutorial.
Burleta a Spock
Video Tutorial
En aquesta secció, veurem com instanciar i inicialitzar Mocks en el marc Spock i com validar les interaccions en el simulador, és a dir, la validació de les trucades als simuladors ocorregudes segons les expectatives del mètode sotmès a prova.
Amb Mocks, no heu de fer moltes configuracions, però podeu validar les interaccions que van passar amb els objectes simulats subministrats a l’aplicació que es prova.
Amb les burles, podeu fer coses com:
- Amb quins arguments es deia la burla?
- Quin va ser el recompte total d’invocacions, etc.?
- Constatant l’ordre dels simulacres.
Vegem un exemple senzill de StudentGradeCalculator, on subministrem l’objecte d’implementació de la base de dades burlada i validem les interaccions amb la simulació. Intentarem entendre les funcions de burla amb exemples senzills.
Tingueu en compte que totes les validacions d’interaccions s’han de fer al bloc “llavors” per convenció.
A continuació es mostra el codi del mètode que es prova (que es dirà a la secció ' Quan: ' bloc)
public String calculateStudentGrade(String studentId) { String grade; // check if grade is already there in database grade = studentDatabase.getStudentGrade(studentId); if(grade!=null && !grade.isEmpty()) { return grade; } List scoreList = studentDatabase.getStudentScores(studentId); Float totalScore = 0F; if(scoreList !=null) totalScore = scoreList.stream().reduce(0F,(a,b)->a+b); if(totalScore > 90) { grade = 'A'; } else if (totalScore > 80) { grade = 'B'; } else { grade = 'C'; } // update the calculated grade in database studentDatabase.updateStudentGrade(studentId, grade); return grade; }
# 1) Validació de les interaccions amb arguments exactes: primer validem les interaccions amb els arguments exactament esperats. Aquí esperarem que es convoquin els mètodes burlats amb els arguments exactes (segons el flux d’execució del mètode).
Aquí “ base de dades estudiant 'És el simulacre d'una interfície de base de dades per a la qual estem validant les interaccions.
def 'illustrate mocks for interaction verification with arguments'() { when: studentReportGenerator.calculateStudentGrade('123'); then: 1*studentDatabase.updateStudentGrade('123','C') 1*studentDatabase.getStudentGrade('123') }
Com es mostra més amunt, estem validant amb els arguments exactes, de manera que s'ha hagut de cridar a la implementació burlada amb. Qualsevol canvi en aquests arguments farà que la prova falli i el registre d'errors mostri el motiu adequat.
Intentem canviar la nota a ' updateStudentGrade ”A“ A ”en lloc de l’anomenat realment“ C ”i vegeu quin error rebem quan s’executa la prova.
Too few invocations for: 1*studentDatabase.updateStudentGrade('123','A') (0 invocations) Unmatched invocations (ordered by similarity): 1 * studentDatabase.updateStudentGrade('123', 'C') 1 * studentDatabase.getStudentScores('123')
Es mostrarà un error com 'Massa poques invocacions', ja que no pot trobar la invocació falsa amb els arguments proporcionats.
# 2) Ara anem a veure com validar les interaccions Mock sense proporcionar els valors dels arguments reals, és a dir, el que ens interessa és saber que el simulacre es va invocar al mètode, però no amb quins arguments.
Aquest tipus de requisits són més freqüents mentre s’escriuen proves unitàries per al codi de producció real, ja que no sempre és fàcil identificar els arguments reals que depenen bàsicament de la lògica de negoci principal de l’aplicació que s’està provant.
La sintaxi és senzilla, només cal utilitzar un subratllat '_' per a un argument on no es conegui el valor real.
Per exemple, per comprovar si hi ha cap valor de cadena, només cal esmentar-ho “_ Com a cadena ”Al lloc d'un argument a la prova i hauria de passar per a qualsevol valor de cadena (de manera similar per a altres tipus de dades tant primitius com personalitzats).
Entenguem això amb un exemple
def 'illustrate mocks for interaction verification with generic matchers'() { when: studentReportGenerator.calculateStudentGrade('123'); then: 1*studentDatabase.updateStudentGrade(_ as String, _ as String) 1*studentDatabase.getStudentGrade('123') }
Un punt important a tenir en compte aquí és que sempre podeu combinar els arguments que es coneixen i el que no es coneix. Per exemple, a l'exemple següent, estem validant la interacció d'un simulacre amb els arguments reals i de l'altre amb els aparells solts.
# 3) Per últim, vegem un escenari en què podem determinar l’ordre d’invocació simulada, és a dir, a quin ordre es deien els simulacres quan s’executa la prova.
De vegades és essencial validar el flux d’esdeveniments quan hi ha diversos col·laboradors / simulacres implicats en l’aplicació que s’està provant i és útil entendre i validar que els mètodes s’han cridat en una seqüència predeterminada.
def 'illustrate mocks for validating order'() { when: studentReportGenerator.calculateStudentGrade('123'); then: 1*studentDatabase.getStudentGrade('123') then: 1*studentDatabase.updateStudentGrade(_ as String, _ as String) }
Això es pot aconseguir simplement utilitzant múltiples blocs 'llavors:' en l'ordre de les expectatives de seqüència de simulacions. Si la seqüència esmentada no compleix l'ordre d'invocació real, es produeix un error que detalla 'Ordre d'invocació incorrecte'.
Per exemple, si canvio l'ordre de l'anterior llavors instruccions, l'execució de la prova generarà un error com es mostra a continuació.
Wrong invocation order for: 1*studentDatabase.updateStudentGrade(_ as String, _ as String) (1 invocation) Last invocation: studentDatabase.updateStudentGrade('123', 'C')
Acoblament a Spock
Video Tutorial
Hem explorat tot sobre Mocking, ara veurem com definir Stubs als objectes burlats. La descomposició no és res més que configurar respostes predefinides o definides a les invocacions falses per provar els diferents fluxos / escenaris de l’aplicació que es prova.
Penseu en això com programar un simulacre per retornar un valor predefinit quan es va cridar. Continuarem amb la mateixa aplicació StudentGradeCalculator i eliminarem les trucades de la interfície de la base de dades per provar diferents escenaris.
Un Stub és com un simulacre que en certa manera emula el comportament de l'objecte real. Podeu simplement anomenar-lo com un simulacre programat.
Sintaxi de reducció
La sintaxi per a l'acoblament és de dos operadors de desplaçament a la dreta, és a dir, ' >> '
Per establir un taló en qualsevol trucada, el podeu definir de la manera següent:
StubbedObject.StubbedMethod(//argumentList) >> “Stubbed Response”
Ara comprenem els diferents escenaris de reducció amb exemples.
# 1) Acoblament amb paràmetres reals: Si els arguments es coneixen amb antelació o si voleu establir stub només quan la invocació és amb arguments especificats, es pot utilitzar aquesta manera d'especificar stubs.
def 'illustrate stubs with exact matchers'() { given: studentDatabase.getStudentScores('123') >> (20F, 30F, 50F) when: def grade = studentReportGenerator.calculateStudentGrade('123') then: grade == 'A' }
Aquí podeu veure que el taló s'ha definit amb un argument exacte, és a dir, StudentId en aquest cas com a '123' (per a qualsevol altre valor, el taló no s'invocarà i es retornarà una resposta per defecte).
# 2) Combinació amb aparelladors indulgents: Si no es coneixen els arguments (o no són importants), podem esmentar-los de manera fluïda, tal com vam fer per als simulacres i la sintaxi continua sent la mateixa, és a dir, el subratllat '_'.
def 'illustrate stubs with loose matchers'() { given: studentDatabase.getStudentScores(_ as String) >> (20F, 30F, 10F) when: def grade = studentReportGenerator.calculateStudentGrade('123') then: grade == 'C' }
# 3) Vegem un altre exemple ràpid en què configurem un taló per llançar una excepció.
Aquests escenaris són molt útils per validar la lògica de maneig d’errors d’una aplicació que s’està provant (com en el món real, no és possible generar totes les excepcions, però es podria configurar un simple registre per retornar qualsevol excepció que vulguem i afirmar-la a el bloc de llavors).
def 'illustrate stubs with exceptions thrown'() { given: studentDatabase.getStudentScores(_ as String) >> {throw new RuntimeException()} when: studentReportGenerator.calculateStudentGrade('123') then: thrown(RuntimeException.class) }
Espionatge a Spock
Els espies es basen en objectes reals és a dir, necessiten la implementació de la interfície i no la interfície abstracta en si. Els espies són potents i us poden permetre obtenir mètodes reals cridats per a l'aplicació que es prova i verificar quins arguments es demanaven els mètodes.
Els espies també permeten definir burles parcials a les instàncies d'objectes espiats. és a dir, suposem que voleu definir el comportament d’alguns mètodes sobre l’objecte, llavors podeu permetre que es cridi a la resta com a trucades de mètodes reals.
Aquests solen ser útils en una situació en què pot haver-hi alguns mètodes d’interfície que no s’implementen i n’hi ha pocs que siguin completament funcionals. Per tant, com a desenvolupador podeu escollir eliminar els no implementats i trucar a les implementacions reals dels mètodes funcionals.
Cal tenir en compte que, per als objectes Spied, tret que es defineixin els esbossos, el comportament per defecte serà cridar a la implementació real. Dit això, no s’ha de trucar sovint als espies i es pot aconseguir tota la cobertura de l’escenari mitjançant simulacres i talons i una combinació d’ells.
Vegem uns quants exemples que utilitzen Spies en el marc Spock amb el mateix exemple de StudentGradeCalculator (Hem creat una implementació real del Base de dades de l’alumne que és una implementació en memòria que utilitza HashMap per il·lustrar trucades a mètodes reals i retorn de dades. El codi estarà disponible a la darrera secció del tutorial):
# 1) Espionatge mitjançant una combinació de trucades de mètodes reals i inicials
def 'illustrate spies'() { given: StudentDatabase spiedStudentDatabase = Spy(StudentDatabase.class) def studentReportGenerator = new StudentReportGenerator(spiedStudentDatabase) when: def grade = studentReportGenerator.calculateStudentGrade('123') then: grade == 'A' 1*spiedStudentDatabase.getStudentGrade(_ as String) >> 'A' }
L'exemple anterior il·lustra la sintaxi per crear Spy mitjançant el framework Spock. El taló es defineix en el moment de la declaració.
A més, les trucades espiades es poden verificar tal com es mostra al bloc de llavors (amb aparelladors d'arguments solts que es poden definir per a qualsevol argument específic).
# 2) Espionatge amb totes les trucades reals de mètodes
def 'illustrate spies with real method call'() { given: StudentDatabase spiedStudentDatabase = Spy(StudentDatabase.class) def studentReportGenerator = new StudentReportGenerator(spiedStudentDatabase) when: def grade = studentReportGenerator.calculateStudentGrade('123') then: grade == 'C' 1*spiedStudentDatabase.getStudentGrade('123') }
A l'exemple anterior, com que no hem esmentat cap comportament obstinat, totes les trucades aniran a la implementació real.
Conclusió
En aquest tutorial, hem après tot sobre les tècniques incorporades a Mock Stub i Spy mitjançant el framework Spock. Spock ho facilita combinant aquestes funcions com a part del propi marc amb una sintaxi groovy més llegible juntament amb el codi de la caldera menor.
Mock, Stubs i Spies s’utilitzen àmpliament en proves unitàries per augmentar la cobertura i provar o validar la lògica de negoci principal de l’aplicació sotmesa a prova.
Codi font de l'aplicació
StudentReportGenerator.java: aquest és el mètode / aplicació que es prova
package app.studentScores; import java.util.List; public class StudentReportGenerator { public IStudentDatabase studentDatabase; public StudentReportGenerator(IStudentDatabase studentDatabase) { this.studentDatabase = studentDatabase; } public String calculateStudentGrade(String studentId) { String grade; // check if grade is already there in database grade = studentDatabase.getStudentGrade(studentId); if(grade!=null && !grade.isEmpty()) { return grade; } List scoreList = studentDatabase.getStudentScores(studentId); Float totalScore = 0F; if(scoreList !=null) totalScore = scoreList.stream().reduce(0F,(a,b)->a+b); if(totalScore > 90) { grade = 'A'; } else if (totalScore > 80) { grade = 'B'; } else { grade = 'C'; } // update the calculated grade in database studentDatabase.updateStudentGrade(studentId, grade); return grade; } }
IStudentDatabase.java: interfície de base de dades
package app.studentScores; import java.util.List; public interface IStudentDatabase { List getStudentScores(String studentId); void updateStudentGrade(String studentId, String grade); String getStudentGrade(String studentId); }
StudentDatabase.java: implementació InMemory de la interfície IStudentDatabase.java
package app.studentScores; import java.util.*; public class StudentDatabase implements IStudentDatabase { private Map scoreMap; private Map gradeMap; public StudentDatabase() { this.scoreMap = new HashMap(); this.gradeMap = new HashMap(); scoreMap.put('123', Arrays.asList(40F, 30F, 30F)); scoreMap.put('456', Arrays.asList(10F, 10F, 30F)); gradeMap.put('123', 'C'); gradeMap.put('456', 'A'); } @Override public List getStudentScores(String studentId) { return scoreMap.get(studentId); } @Override public void updateStudentGrade(String studentId, String grade) { gradeMap.put(studentId,grade); } @Override public String getStudentGrade(String studentId) { return gradeMap.get(studentId); } }
Al nostre proper tutorial, veurem com integrar el framework Spock amb altres frameworks i tecnologies de proves.
Lectura recomanada
- Proves d’unitat d’escriptura amb Spock Framework
- Preguntes d'entrevistes de Spock amb respostes (més populars)
- Spock per a la integració i proves funcionals amb seleni
- Proves basades en dades o parametritzades amb Spock Framework
- Spock Tutorial: proves amb Spock i Groovy
- Millor sèrie de tutorials C # GRATU :TS: la millor guia C # per a principiants
- Prova de càrrega amb tutorials HP LoadRunner
- Funcions de data i hora a C ++ amb exemples