Este documento describe cómo Groovy puede usarse para realizar pruebas en la JVM de forma rápida y eficiente. Groovy es un lenguaje dinámico basado en Java que facilita características de programación modernas como pruebas unitarias, mocks y procesamiento de XML. Groovy permite escribir menos código para pruebas gracias a su sintaxis simplificada para mapas, listas y closures.
2. Incrementar la productividad al
realizar pruebas en la JVM
( y por qué no?, también la
producción de endorfinas)
SG09 Andres Almiray 2
3. • Qué es Groovy?
• Groovy y frameworks de pruebas
• Groovy en la runtina diaria
• Mocks
• Procesando XML
• Información adicional
SG09 Andres Almiray 3
4. • Groovy es un lenguaje ágil y dinámico
para la Máquina Virtual de Java
• Basado en los conceptos base del lenguaje
Java, incluye características inspiradas en
otros lenguajes como Python, Smalltalk y
Ruby
• Habilita características de programación
modernas con una curva de aprendizaje
plana para desarrolladores Java
SG09 Andres Almiray 4
5. • Soporta Lenguajes de Dominio
Específico y otras características de
sintaxis corta.
• Simplifica el ciclo de pruebas dado que
soporta pruebas unitarias y mocking desde
el inicio.
SG09 Andres Almiray 5
6. HelloWorld.java
public 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
7. HelloWorld.groovy
public 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
8. Equivalente 100% Groovy
class HelloWorld {
String name
def greet() { "Hello $name" }
}
def helloWorld = new HelloWorld(name:"Groovy")
println helloWorld.greet()
SG09 Andres Almiray
9. 1er Mantra
Java es Groovy, Groovy es Java
Groovy
• Toda clase Java es una clase Groovy, la
Groovy
proposición inversa también es verdadera.
• Groovy tiene el mismo modelo de memoria
y seguridad que Java.
• El 98% de código Java es código Groovy,
Groovy
en casi todo los casos basta renombrar
*.java por *.groovy
SG09 Andres Almiray
10. 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
Groovy 1.7beta1 donde solo existe soporte
para clases anónimas).
SG09 Andres Almiray
11. 2ndo Mantra
Groovy es Java y Groovy NO es Java
• Curva de aprendizaje prácticamente plana.
• Empieza con sintaxis Java, emigra a
sintaxis Groovy conforme pase el tiempo.
• Groovy provee closures, meta
programación, nuevos operadores,
sobrecarga de operadores, sintaxis nativa
para Mapas y Listas, tipado opcional, etc...
SG09 Andres Almiray
12. Groovy y los frameworks de Prueba
• Cualquier script de Groovy puede
convertirse en un caso de prueba
• assert habilitado desde el inicio
• Groovy provee GroovyTestCase como
clase base
• Soporte de Junit 3.x/4.x y TestNG.
• Groovy permite el uso de características de
JDK5+
• anotaciones, enums, tipos genéricos
SG09 Andres Almiray
13. Groovy 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
14. Acceso de propieades
// Java
public class Bean {
private String name;
public void setName(String n) { name = n; }
public String getName() { return name; }
}
// Groovy
Bean bean = new Bean(name: “Duke”)
assert bean.name == “Duke”
bean.name = “Tux”
assert bean.name == “Tux”
assert bean.name == bean.getName()
SG09 Andres Almiray
15. Mapas y Listas
Map map = [:]
assert map instanceof java.util.Map
map["key1"] = "value1"
map.key2 = "value2"
assert map.size() == 2
assert map.key1 == "value1"
assert map["key2"] == "value2"
List list = []
assert list instanceof java.util.List
list.add("One")
list << "Two"
assert list.size() == 2
assert ["One","Two"] == list
SG09 Andres Almiray
17. Closures (2)
// un closure con 3 parámetros, el tercero es
// opcional dado que define un valor por omisión
def 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
18. Transformaciones de AST
import java.text.SimpleDateFormat
class 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
19. Transformaciones de AST
•@Singleton
•@Lazy
•@Delegate
•@Immutable
•@Bindable
•@Newify
•@Category/@Mixin
•@PackageScope
SG09 Andres Almiray
20. 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
21. Probando excepciones en Java
public 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
22. Probando excepciones en Groovy
class GroovyExceptionTestCase extends GroovyTestCase {
void testExceptionThrowingCode() {
shouldFail( UnsupportedOperationException ){
new MyService().doSomething()
}
}
}
SG09 Andres Almiray
23. Mocking
• Groovy 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
26. 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
Groovy
SG09 Andres Almiray
29. 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
30. 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
31. 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