Realizando Pruebasen la JVM con Velocidady Eficacia
Andres Almiray
SG09 Andres Almiray 2
Incrementar la productividad al Incrementar la productividad al realizar pruebas en la JVMrealizar pruebas en la JVM
((y por qué no?, también la y por qué no?, también la producción de endorfinas)producción de endorfinas)
SG09 Andres Almiray 3
• Qué es Qué es GroovyGroovy??
• GroovyGroovy y frameworks de pruebas y frameworks de pruebas
• GroovyGroovy en la runtina diaria en la runtina diaria
• MocksMocks
• Procesando XMLProcesando XML
• Información adicionalInformación adicional
SG09 Andres Almiray 4
• GroovyGroovy es un lenguaje es un lenguaje ágilágil y y dinámico dinámico para la Máquina Virtual de Javapara la Máquina Virtual de Java
• Basado en los conceptos base del lenguaje Basado en los conceptos base del lenguaje Java, incluye características inspiradas en Java, incluye características inspiradas en otros lenguajes como Python, Smalltalk y otros lenguajes como Python, Smalltalk y RubyRuby
• Habilita Habilita características de programación características de programación modernasmodernas con una curva de aprendizaje con una curva de aprendizaje plana para desarrolladores Javaplana para desarrolladores Java
SG09 Andres Almiray 5
• Soporta Soporta Lenguajes de Dominio Lenguajes de Dominio EspecíficoEspecífico y otras características de y otras características de sintaxis corta.sintaxis corta.
• Simplifica el ciclo de pruebas dado que Simplifica el ciclo de pruebas dado que soporta pruebas unitarias y soporta pruebas unitarias y mockingmocking desde desde el inicio.el inicio.
SG09 Andres Almiray
HelloWorld.javapublic class HelloWorld { String name;
public void setName(String name) { this.name = name; } public String getName(){ return name; }
public String greet() { return “Hello “+ name; }
public static void main(String args[]){ HelloWorld helloWorld = new HelloWorld(); helloWorld.setName(“Groovy”); System.err.println( helloWorld.greet() ); }}
SG09 Andres Almiray
HelloWorld.groovypublic class HelloWorld { String name;
public void setName(String name) { this.name = name; } public String getName(){ return name; }
public String greet() { return “Hello “+ name; }
public static void main(String args[]){ HelloWorld helloWorld = new HelloWorld(); helloWorld.setName(“Groovy”); System.err.println( helloWorld.greet() ); }}
SG09 Andres Almiray
Equivalente 100% Groovyclass HelloWorld { String name def greet() { "Hello $name" }}
def helloWorld = new HelloWorld(name:"Groovy")println helloWorld.greet()
SG09 Andres Almiray
1er Mantra
Java es GroovyGroovy, GroovyGroovy es Java
• Toda clase Java es una clase GroovyGroovy, la proposición inversa también es verdadera.
• GroovyGroovy tiene el mismo modelo de memoria y seguridad que Java.
• El 98% de código Java es código GroovyGroovy, en casi todo los casos basta renombrar *.java por *.groovy
SG09 Andres Almiray
Cuidado con...
• La inicialización de arreglos no esta soportada, pero se puede convertir una Lista en un arreglo.
• Clases internas no soportadas (excepto en GroovyGroovy 1.7beta1 donde solo existe soporte para clases anónimas).
SG09 Andres Almiray
2ndo Mantra
GroovyGroovy es Java y GroovyGroovy NO es Java
• Curva de aprendizaje prácticamente plana.
• Empieza con sintaxis Java, emigra a sintaxis GroovyGroovy conforme pase el tiempo.
• GroovyGroovy provee closures, meta programación, nuevos operadores, sobrecarga de operadores, sintaxis nativa para Mapas y Listas, tipado opcional, etc...
SG09 Andres Almiray
GroovyGroovy y los frameworks de Prueba
• Cualquier script de GroovyGroovy puede convertirse en un caso de prueba
• assert habilitado desde el inicio
• GroovyGroovy provee GroovyTestCase como clase base
• Soporte de Junit 3.x/4.x y TestNG.
• GroovyGroovy permite el uso de características de JDK5+
• anotaciones, enums, tipos genéricos
SG09 Andres Almiray
GroovyGroovy en la rutina diaria
• Escribe menos dado que algunas palabras reservadas son opcionales
• public, private, protected, return
• Azúcar sintáctica para uso de propiedades
• Sintaxis nativa para Mapas y Listas
• Closures
• Transformaciones de AST (Arbol de Sintaxis Abstracto) meta programación en tiempo de compilación
SG09 Andres Almiray
Acceso de propieades// Javapublic class Bean { private String name; public void setName(String n) { name = n; } public String getName() { return name; }}
// GroovyBean bean = new Bean(name: “Duke”)assert bean.name == “Duke”bean.name = “Tux”assert bean.name == “Tux”assert bean.name == bean.getName()
SG09 Andres Almiray
Mapas y Listas
Map map = [:]assert map instanceof java.util.Mapmap["key1"] = "value1"map.key2 = "value2"assert map.size() == 2assert map.key1 == "value1"assert map["key2"] == "value2"
List list = []assert list instanceof java.util.Listlist.add("One")list << "Two"assert list.size() == 2assert ["One","Two"] == list
SG09 Andres Almiray
Closures (1)int count = 0def closure = {-> 0.upto(10) { count += it }}closure()assert count == (10*11)/2
def runnable = closure as Runnableassert runnable instanceof java.lang.Runnablecount = 0runnable.run()assert count == (10*11)/2
SG09 Andres Almiray
Closures (2)// un closure con 3 parámetros, el tercero es// opcional dado que define un valor por omisióndef getSlope = { x, y, b = 0 -> println "x:${x} y:${y} b:${b}" (y - b) / x}
assert 1 == getSlope( 2, 2 )def getSlopeX = getSlope.curry(5)assert 1 == getSlopeX(5)assert 0 == getSlopeX(2.5,2.5)// prints// x:2 y:2 b:0// x:5 y:5 b:0// x:5 y:2.5 b:2.5
SG09 Andres Almiray
Transformaciones de AST
import java.text.SimpleDateFormatclass Event { @Delegate Date when String title, url}def df = new SimpleDateFormat("dd/MM/yyyy")def sg09 = new Event(title: "SG 09", url: "http://www.sg.com.mx/sg09/", when: df.parse("28/09/2009"))def so2gx = new Event(title: "SpringOne2GX", url: "http://www.springone2gx.com/", when: df.parse("19/10/2009"))
assert sg09.before(so2gx.when)
SG09 Andres Almiray
Transformaciones de AST•@Singleton•@Lazy•@Delegate•@Immutable•@Bindable•@Newify•@Category/@Mixin•@PackageScope
SG09 Andres Almiray
Pero... cómo ejecuto las pruebas?
• Usa to IDE favorito• IDEA
• Eclipse
• NetBeans
• Herramientas de línea de comando• Ant
• Gant
• Maven
• Gradle
• GroovyShell y GroovyConsole
SG09 Andres Almiray
Probando excepciones en Javapublic class JavaExceptionTestCase extends TestCase { public void testExceptionThrowingCode() { try { new MyService().doSomething(); fail("MyService.doSomething has been implemented"); }catch( UnsupportedOperationException expected ){ // todo esta BIEN si llegamos a este punto! }
}}
SG09 Andres Almiray
Probando excepciones en GroovyGroovyclass GroovyExceptionTestCase extends GroovyTestCase { void testExceptionThrowingCode() { shouldFail( UnsupportedOperationException ){ new MyService().doSomething() } }}
SG09 Andres Almiray
Mocking
• GroovyGroovy no tiene problemas con librerías Java
• EasyMock – record/replay
• JMock – define expectativas en el camino
• Mockito – el recién llegado a la fiesta
• Proxis dinámicos
• StubFor/MockFor
SG09 Andres Almiray
Proxies Dinámicos
SG09 Andres Almiray
SG09 Andres Almiray
StubFor/MockFor
• ejecutor – colaborador• mocks/stubs definen expectativas en los
colaboradores• mocks son estrictos, las expectativas deben ser
ejecutadas en orden y cardinalidad exacta• stubs son mas laxos, las expectativas pueden ser
ejecutadas en cualquier orden pero la cardinalidad debe ser respetada.
• ALERTA: usar solo cuando el ejecutor es código GroovyGroovy
SG09 Andres Almiray
Groovy Mocks
SG09 Andres Almiray
SG09 Andres Almiray
Procesando XML
• DbUnit: extensión de Junit para verificar bases de datos
• Existen varias opciones– Típica: extender de DatabaseTestCase
– Flexible: usar un IDatabaseTester compuesto
– BYOT: (Build Your Own Testcase)
SG09 Andres Almiray
XML en linea
import org.dbunit.*import org.junit.*
class MyDBTestCase { IDatabaseTester db
@BeforeClass void init(){ db = new JdbcDatabaseTester("org.hsqldb.jdbcDriver", "jdbc:hsqldb:sample", "sa", "" ) // insert table schema def dataset = """ <dataset> <company name="Acme"/> <employee name="Duke" company_id="1"> </dataset> """ db.dataset = new FlatXmlDataSet( new StringReader(dataset) ) db.onSetUp() }
@AfterClass void exit() { db.onTearDown() }}
SG09 Andres Almiray
XML verificado por el compilador
import org.dbunit.*import org.junit.*Import groovy.xml.MarkupBuilder
class MyDBTestCase { IDatabaseTester db
@BeforeClass void init(){ db = new JdbcDatabaseTester("org.hsqldb.jdbcDriver", "jdbc:hsqldb:sample", "sa", "" ) // insert table schema def dataset = new MarkupBuilder().dataset { company( name: Acme ) employee( name: "Duke", company_id: 1 ) } db.dataset = new FlatXmlDataSet( new StringReader(dataset) ) db.onSetUp() }
@AfterClass void exit() { db.onTearDown() }}
SG09 Andres Almiray
Información Adicional
http://groovy.codehaus.org
http://junit.org
http://testng.org
http://dbunit.org
http://groovy.dzone.com
http://gr8forums.org
twitter: @aalmirayblog: http://jroller.com/aalmiray