leanmind logo leanmind text logo

Blog

TDD Avanzado

Las herramientas que se necesitan para aplicar TDD en el mundo real en cualquier proyecto.

Testeando con Spock

Por José Luis Rodríguez Alonso

A la hora de testear con Java, la primera opción que me viene a la cabeza es JUnit, pero hay otras alternativas interesantes… Hoy vamos a probar con Spock.

Spock

¿Qué es Spock?

Spock es un framework para realizar tests en proyectos Java. La principal diferencia con JUnit, es que los tests se escriben en Groovy, dándote acceso a una sintáxis más expresiva.

Configuración

Lo primero que debemos hacer, como siempre, es añadir las dependencias a nuestro proyecto.

Para Gradle:

1
testCompile 'org.spockframework:spock-core:1.1-groovy-2.4-rc-2'

Para Maven:

1
2
3
4
5
6
<dependency>
    <groupId>org.spockframework</groupId>
    <artifactId>spock-core</artifactId>
    <version>1.1-groovy-2.4-rc-2</version>
    <scope>test</scope>
</dependency>

Y, dado que los tests los vamos a crear en Groovy, también es necesario configurar el proyecto para ello:

1
2
3
4
5
plugins {
   id 'groovy'
}

implementation 'org.codehaus.groovy:groovy:2.5.9'

Con esto, ya podemos picar código Groovy en nuestro proyecto.

Nota: Solo incluyo la configuración para Gradle, porque la de Maven son muchas líneas :D Busca por Groovy + Maven si estás interesado ;)

Conceptos

En Spock hay varios conceptos similares a JUnit, pero con distinto nombre:

Ejemplos

Como mejor se entiende Spock es viendo ejemplos, así que al lío.


El primer ejemplo es uno sencillo para ver la sintaxis:

1
2
3
4
5
6
7
class MyFirstTest extends Specification {

	def "one plus one is two"() {
		expect:
		1 + 1 == 2
	}
}

Aquí ya vemos alguna ventaja de usar Groovy respecto a Java: ¡podemos definir los tests usando strings!, se acabó el camelCase o los underscores :yum:


En el segundo ejemplo, vamos a usar un poco más los bloques:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class AccountSpec extends Specification {

    def "adding credit to an account increases the account's balance"() {

		given: "an empty bank account"
		def account = new Account()

		when: "the account is credited $10"
		account.addCredit(10)

		then: "the account's balance is $10"
		account.balance == 10
    }
}

Los bloques nos ayudan a estructurar el test y, gracias al comentario (opcional), también ayudan a entenderlo. Otra cosa interesante es que no necesitamos una librería para realizar los assertions, basta con añadir nuestras comprobaciones en el bloque then o expect, mientras retornen un boolean es suficiente para marcar el test como verde o rojo.


El tercer ejemplo consiste en usar tablas de datos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class CalculatorSpec extends Specification {

	def "returns the maximum of two numbers"() {

		expect:
		Calculator.max(a, b) == c
	
		where:
		a | b || c
		1 | 2 || 2
		5 | 0 || 5
		0 | 0 || 0
	}
}

JUnit también permite hacer tests parametrizados, pero la sintaxis de Groovy aquí es mucho más sencilla y directa. Además, los mensajes de error en Spock son muy claros en estos casos:

1
2
3
4
5
6
CalculatorSpec > returns the maximum of two numbers FAILED
    Condition not satisfied:
    Calculator.max(a, b) == c
               |   |  |  |  |
               2   1  2  |  1
                         false

Y, un último ejemplo… está vez usando Mocks. Spock tiene su propia forma de mockear objetos usando algunas particularidades de Groovy.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class CustomerServiceSpec extends Specification {

	def "returns existing customers"() {

		given: "a repository that returns two customers"
		def customerRepository = Mock(CustomerRepository)
		customerRepository.findAll() >> [ "Customer 1", "Customer 2" ]

		and: "a service using that repository"
		def customerService = new CustomerService(customerRepository)

		when:
		def customers =	customerService.findCustomers();

		then:
		customers.size() == 2
	}
}

How cool is that!? :D Usando el operador » de Groovy, indicamos lo que queremos retornar en nuestro mock. También es posible verificar que el método se ha ejecutado, lanzar excepciones y otras cosas típicas de los mocks/stubs.

Conclusión

Aunque al principio da la sensación de que el framework está un poco muerto, en realidad hay una versión 2.0 en camino que lo reescribe para adaptarse a JUnit 5. También hay proyectos potentes, como Micronaut que lo utilizan como opción principal.

Personalmente, esta es la primera vez que lo uso, por lo que no estoy en condiciones de recomendarlo, pero lo que he visto me ha gustado mucho. Seguiremos informando :)

Publicado el 18/08/2021 por
José Luis image

José Luis Rodríguez Alonso

¿Quieres más? te invitamos a suscribirte a nuestro boletín para avisarte cada vez que recopilemos contenido de calidad que compartir.

Si disfrutas leyendo nuestro blog, ¿imaginas lo divertido que sería trabajar con nosotros? ¿te gustaría?

Impulsamos el crecimiento profesional de tu equipo de developers