Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Framework de test spock

636 views

Published on

Sesión dedicada al framework de tests Spock impartida en el Experto Java de la Universidad de Alicante. http://web.ua.es/expertojava

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

Framework de test spock

  1. 1. Framework Grails Sesión 6: Framework de test Spock. 12
  2. 2. Índice Introducción a los tests Framework de test Spock Spock en Grails
  3. 3. Introducción a los tests ¿Qué son los tests? Tipos de tests de software Otros frameworks de tests
  4. 4. ¿Qué son los tests? Los tests de software se pueden definir como el proceso empleado para comprobar la corrección de un programa informático y se puede considerar como una parte más en el proceso del control de calidad.
  5. 5. Tipos de tests de software Tests unitarios Tests de integración Tests funcionales
  6. 6. Otros frameworks de tests JUnit TestNG
  7. 7. Características de Spock Fácil de aprender Integración con Groovy Eliminación aserciones innecesarias Información detallada en las salidas de los tests Diseñado desde el punto de vista del usuario TDD, BDD, etc Lenguaje altamente expresivo Compatible con JUnit Combina ideas de otros frameworks como JUnit o jMock
  8. 8. Instalación de Spock en Grails BuildConfig.groovy grails.project.dependency.resolution={ repositories{ grailsCentral() mavenCentral() } dependencies{ test"org.spockframework:spock-grails-support:0.7-groovy-2.0" } plugins{ test(":spock:0.7"){ exclude"spock-grails-support" } } }
  9. 9. Instalación de Spock en Grails grailstest-app
  10. 10. Tests en Spock Extienden spock.lang.Specification packagees.ua.expertojava.todo importspock.lang.Specification classMyFirstTestextendsSpecification{ def"Eloperadorsumafuncionacorrectamente"(){ expect: 10==2+8 and: 10==0+10 and: 10==10+0 } }
  11. 11. A tener en cuenta Sintaxis muy sencilla de leer Nombre de los métodos entrecomillados No son necesarias las aserciones
  12. 12. Tests en Spock def"Elmétodoplusdelosnúmerosfuncionacorrectamente"(){ when: defresult=10.plus(2) then: result==12 }
  13. 13. A tener en cuenta Bloque when lanza el método a probar Bloque then comprueba la respuesta
  14. 14. Tests en Spock @Unroll def"Elmétodoplusfuncionaconelsumador#sumadoryelsumando#sumando"(){ when: defresult=sumador.plus(sumando) then: result==resultadoEsperado where: sumador| sumando | resultadoEsperado 0 | 0 | 0 0 | 1 | 1 1 | 1 | 2 -1 | 0 | -1 0 | -1 | -1 -1 | -1 | -2 2 | 1 | 3 }
  15. 15. A tener en cuenta Tenemos una batería de pruebas con datos diferentes Utilizamos placeholders en el nombre del test Unroll despliega cada conjunto de datos como un test nuevo
  16. 16. Resultado sin @Unroll
  17. 17. Tests en Spock @Unroll def"Elmétodoplusfuncionaconelsumador#sumadoryelsumando#sumandoutilizandolistas"(){ when: defresult=sumador.plus(sumando) then: result==resultadoEsperado where: sumador<<[0,0,1,-1,0,-1,2] sumando<<[0,1,1,0,-1,-1,1] resultadoEsperado<<[0,1,2,-1,-1,-2,3] }
  18. 18. Tests en Spock def"Elmétodoparaconcatenarcadenasañadeunsigno+entrelascadenasconcatenadas"(){ given: String.metaClass.concat={Stringc-> "${delegate}+${c}" } expect: "cadena1".concat("cadena2")=="cadena1+cadena2" cleanup: String.metaClass=null }
  19. 19. A tener en cuenta Bloque given para preparar el test Bloque cleanup para dejar las cosas como estaban
  20. 20. Spock en Grails Tests sobre clases de dominio Tests sobre contraladores Tests sobre librerías de etiquetas, vistas y plantillas Tests sobre servicios Tests mockeando objetos Algunas anotaciones interesantes
  21. 21. Métodos predefinidos setupSpec(), se ejecuta antes del primer test de una determinada clase de tests con Spock cleanupSpec(), se ejecuta después del último test de una determinada clase de tests con Spock setup(), se ejecuta antes de cada test de una determinada clase de tests con Spock setupSpec(), se ejecuta después de cada test de una determinada clase de tests con Spock
  22. 22. Tests sobre clases de dominio en Grails packagees.ua.expertojava.todo classCategory{ Stringname Stringdescription statichasMany=[todos:Todo] staticconstraints={ name(blank:false) description(blank:true,nullable:true,maxSize:1000) } StringtoString(){ name } }
  23. 23. Tests sobre clases de dominio en Grails packagees.ua.expertojava.todo importgrails.test.mixin.TestFor importspock.lang.Specification importspock.lang.Unroll /** *SeetheAPIfor{@linkgrails.test.mixin.domain.DomainClassUnitTestMixin}forusageinstructions */ @TestFor(Category) classCategorySpecextendsSpecification{ defsetup(){ } defcleanup(){ } ...
  24. 24. Tests sobre clases de dominio en Grails def"Elnombredelacategoríanopuedeserlacadenavacía"(){ given: defc1=newCategory(name:"") when: c1.validate() then: c1?.errors['name'] }
  25. 25. Tests sobre clases de dominio en Grails def"Sielnombrenoeslacadenavacía,estecamponodaráproblemas"(){ given: defc1=newCategory(name:"algo") when: c1.validate() then: !c1?.errors['name'] }
  26. 26. Tests sobre clases de dominio en Grails def"Siladescripcióneslacadenavacía,estecamponodaráproblemas"(){ given: defc1=newCategory(description:"") when: c1.validate() then: !c1?.errors['description'] }
  27. 27. Tests sobre clases de dominio en Grails def"Ladescripcióndelacategoríapuedesernull"(){ given: defc1=newCategory(description:null) when: c1.validate() then: !c1?.errors['description'] }
  28. 28. Tests sobre clases de dominio en Grails @Unroll def"Siladescripcióntienemenosde1001caracteres,nodaráproblemas"(){ given: defc1=newCategory(description:"a"*characters) when: c1.validate() then: !c1?.errors['description'] where: characters<<[0,1,999,1000] }
  29. 29. Tests sobre clases de dominio en Grails @Unroll def"Siladescripcióntienemás1000caracteres,daráproblemas"(){ given: defc1=newCategory(description:"a"*characters) when: c1.validate() then: c1?.errors['description'] where: characters<<[1001,1002] }
  30. 30. Tests sobre clases de dominio en Grails def"LainstanciadeCategoríadevuelvesunombrepordefecto"(){ expect: newCategory(name:"Thecategoryname").toString()=="Thecategoryname" }
  31. 31. pto. Ciencia de la Computación e I.A. Sesión 6 Tests sobre controladores en Grails packagees.ua.expertojava.todo importgrails.test.mixin.* importspock.lang.* @TestFor(CategoryController) @Mock(Category) classCategoryControllerSpecextendsSpecification{ defpopulateValidParams(params){ assertparams!=null //TODO:Populatevalidpropertieslike... //params["name"]='someValidName' } ...
  32. 32. Tests sobre controladores en Grails defpopulateValidParams(params){ assertparams!=null params["name"]='Categoryname' }
  33. 33. Tests sobre controladores en Grails grailstest-appCategoryControllerSpecunit:
  34. 34. Tests sobre controladores en Grails packagees.ua.expertojava.todo importgrails.test.mixin.* importspock.lang.* @TestFor(CategoryController) @Mock(Category) classCategoryControllerSpecextendsSpecification{ defpopulateValidParams(params){ assertparams!=null params["name"]='Categoryname' } ... }
  35. 35. Tests sobre controladores en Grails void"Testtheindexactionreturnsthecorrectmodel"(){ when:"Theindexactionisexecuted" controller.index() then:"Themodeliscorrect" !model.categoryInstanceList model.categoryInstanceCount==0 }
  36. 36. Tests sobre controladores en Grails void"Testthecreateactionreturnsthecorrectmodel"(){ when:"Thecreateactionisexecuted" controller.create() then:"Themodeliscorrectlycreated" model.categoryInstance!=null }
  37. 37. Tests sobre controladores en Grails void"Testthesaveactioncorrectlypersistsaninstance"(){ when:"Thesaveactionisexecutedwithaninvalidinstance" request.contentType=FORM_CONTENT_TYPE request.method='POST' defcategory=newCategory() category.validate() controller.save(category) then:"Thecreateviewisrenderedagainwiththecorrectmodel" model.categoryInstance!=null view=='create' when:"Thesaveactionisexecutedwithavalidinstance" response.reset() populateValidParams(params) category=newCategory(params) controller.save(category)
  38. 38. Tests sobre controladores en Grails void"Testthattheshowactionreturnsthecorrectmodel"(){ when:"Theshowactionisexecutedwithanulldomain" controller.show(null) then:"A404errorisreturned" response.status==404 when:"Adomaininstanceispassedtotheshowaction" populateValidParams(params) defcategory=newCategory(params) controller.show(category) then:"Amodelispopulatedcontainingthedomaininstance" model.categoryInstance==category }
  39. 39. Tests sobre controladores en Grails void"Testthattheeditactionreturnsthecorrectmodel"(){ when:"Theeditactionisexecutedwithanulldomain" controller.edit(null) then:"A404errorisreturned" response.status==404 when:"Adomaininstanceispassedtotheeditaction" populateValidParams(params) defcategory=newCategory(params) controller.edit(category) then:"Amodelispopulatedcontainingthedomaininstance" model.categoryInstance==category }
  40. 40. Tests sobre controladores en Grails void"Testthatthedeleteactiondeletesaninstanceifitexists"(){ when:"Thedeleteactioniscalledforanullinstance" request.contentType=FORM_CONTENT_TYPE request.method='DELETE' controller.delete(null) then:"A404isreturned" response.redirectedUrl=='/category/index' flash.message!=null when:"Adomaininstanceiscreated" response.reset() populateValidParams(params) defcategory=newCategory(params).save(flush:true) then:"Itexists" Category.count()==1 when:"Thedomaininstanceispassedtothedeleteaction"
  41. 41. A tener en cuenta Variables inyectadas: controller, model, view, response, request y flash Anotación @Mock Ejecutar controller.method() Variable model para comprobar el modelo devuelto Redirecciones con response.redirectedUrl
  42. 42. Tests sobre librerías de etiquetas, vistas y plantillas defincludeJs={attrs-> out<<"<scriptsrc="scripts/${attrs['script']}.js"></script>" }
  43. 43. Tests sobre librerías de etiquetas, vistas y plantillas void"LaetiquetaincludeJsdevuelveunareferenciaalalibreríajavascriptpasadaporparámetro"(){ expect: applyTemplate('<todo:includejsscript=""></todo:includejs>')=="<scriptsrc="scripts/.js" applyTemplate('<todo:includejsscript="myfile"></todo:includejs>')=="<scriptsrc="scripts/myf }
  44. 44. Tests sobre librerías de etiquetas, vistas y plantillas void"Elpiedepáginaserenderizacorrectamente"(){ when: defresult=render(template:'/common/footer') then: result=="<divclass=""footer""role=""contentinfo"">n"+ " ©2015ExpertoenDesarrollodeAplicacionesWebconJavaEEyJavascript<br>n"+ " AplicaciónTodocreadaporFranciscoJoséGarcíaRico(21.542.334F)n"+ "</div>" }
  45. 45. Tests sobre servicios en Grails packagees.ua.expertojava.todo importgrails.test.mixin.TestFor importspock.lang.Specification /** *SeetheAPIfor{@linkgrails.test.mixin.services.ServiceUnitTestMixin}forusageinstructions */ @TestFor(TodoService) classTodoServiceSpecextendsSpecification{ defsetup(){ } defcleanup(){ } void"testsomething"(){ }
  46. 46. Tests sobre servicios en Grails defgetNextTodos(Integerdays,params){ Datenow=newDate(System.currentTimeMillis()) Dateto=now+days Todo.findAllByDateBetween(now,to,params) }
  47. 47. Tests sobre servicios en Grails void"ElmétodogetNextTodosdevuelvelossiguientestodosdelosdíaspasadoporparámetro"(){ given: deftodoDayBeforeYesterday=newTodo(title:"Tododaybeforeyesterday",date:newDate()- deftodoYesterday=newTodo(title:"Todoyesterday",date:newDate()-1) deftodoToday=newTodo(title:"Todotoday",date:newDate()) deftodoTomorrow=newTodo(title:"Todotomorrow",date:newDate()+1) deftodoDayAfterTomorrow=newTodo(title:"Tododayaftertomorrow",date:newDate()+ deftodoDayAfterDayAfterTomorrow=newTodo(title:"Tododayaftertomorrow",date:newDate()+ and: mockDomain(Todo,[todoDayBeforeYesterday,todoYesterday,todoToday,todoTomorrow,todoDayAfterTo and: defnextTodos=service.getNextTodos(2,[:]) expect: Todo.count()==6 and: nextTodos.containsAll([todoTomorrow,todoDayAfterTomorrow]) nextTodos.size()==2 and: !nextTodos.contains(todoDayBeforeYesterday)
  48. 48. Tests con Spock mockeando objetos @Unroll void"ElmétodoprintIconFromBooleandevuelveunarutaaunaimagen"(){ when: defoutput=applyTemplate('<todo:printiconfrombooleanvalue="${value}"></todo:printiconfromboo then: output==expectedOutput where: value | expectedOutput true | "icontrue.png" false | "iconfalse.png" }
  49. 49. Tests con Spock mockeando objetos @Unroll void"ElmétodoprintIconFromBooleandevuelveunarutaaunaimagen"(){ given: defassetsTagLib=Mock(AssetsTagLib) tagLib.metaClass.asset=assetsTagLib when: defoutput=applyTemplate('<todo:printiconfrombooleanvalue="${value}"></todo:printiconfromboo then: output==expectedOutput and: 1*assetsTagLib.image(_)>>{value?"icontrue.png":"iconfalse.png"} where: value | expectedOutput true | "icontrue.png" false | "iconfalse.png" }
  50. 50. A tener en cuenta Mockeamos la librería AssetsTagLib Indicamos cuantas interacciones se van a producir con nuestro objecto mockeado Utilizamos placeholder para los parámetros
  51. 51. Algunas anotaciones interesantes @Ignore @Ignore def"myfeature"(){...} @Ignore classMySpecextendsSpecification{...} @Ignore(reason="TODO") def"myfeature"(){...}
  52. 52. Algunas anotaciones interesantes @IgnoreRest def"I'llbeignored"(){...} @IgnoreRest def"I'llrun"(){...} def"I'llalsobeignored"(){...}
  53. 53. Algunas anotaciones interesantes @IgnoreIf @IgnoreIf({System.getProperty("os.name").contains("windows")}) def"I'llruneverywherebutonWindows"(){...}
  54. 54. Algunas anotaciones interesantes @IgnoreIf sys, un mapa con todas las propiedades del sistema env, un mapa con todas las variables de entorno os, información acerca del sistema operativo jvm, información sobre la máquina virtual de Java
  55. 55. Algunas anotaciones interesantes @Requires @Requires({os.windows}) def"I'llonlyrunonWindows"(){...}
  56. 56. Algunas anotaciones interesantes @Stepwise Respeta el orden de los tests
  57. 57. Algunas anotaciones interesantes @Timeout @Timeout(5) def"IfailifIrunformorethanfiveseconds"(){...} @Timeout(value=100,unit=TimeUnit.MILLISECONDS) def"Ibetterbequick"{...}
  58. 58. Algunas anotaciones interesantes @Timeout @Timeout(10) classTimedSpecextendsSpecification{ def"Ifailaftertenseconds"(){...} def"Metoo"(){...} @Timeout(value=250,unit=MILLISECONDS) def"Ifailmuchfaster"(){...} }
  59. 59. Algunas anotaciones interesantes @ConfineMetaClassChanges @Stepwise classFooSpecextendsSpecification{ @ConfineMetaClassChanges def"Irunfirst"(){ when: String.metaClass.someMethod={delegate} then: String.metaClass.hasMetaMethod('someMethod') } def"Irunsecond"(){ when: "Foo".someMethod() then: thrown(MissingMethodException) } }
  60. 60. Algunas anotaciones interesantes @ConfineMetaClassChanges @Title("Thisiseasytoread") classThisIsHarderToReadSpecextendsSpecification{ ... } @Narrative("""" Asauser Iwantfoo Sothatbar """) classGiveTheUserFooSpec(){...}
  61. 61. ¿Preguntas...?
  62. 62. Ejercicios

×