Bit - loader

BDDevelopment en Java con JBehave

   Artículo | Testing Bit - BDDevelopment en Java con JBehave
Ricardo Ahumada | 01/12/17

Siguiendo esta serie de artículos sobre TDD y BDD, vamos a revisar las opciones que tenemos en Java para hacer BDD y revisar el caso concreto de JBehave.

 

Frameworks para Java

Para java existen unos cuantos frameworks que nos permiten hacer BDD:

  • JDave: Enfocado en el testing de las especificaciones (su concepto principal es una Specification). No es un framework estrictamente BDD. Se pude integrar con maven, pero solo sirve para testing a escala pequeña y tiene una sintaxis compleja.

 

  • Easyb: Es un framework con una sintaxis sencilla y muy fácil de usar. Usa Groovy como lenguaje, algo que puede ser una limitación. Cubre todo lo necesario para hacer BDD, ya que soporta el testing tanto las historias y las especificaciones. Asimismo nos permite crear informes en HTML sencillos. En contra necesita su propio plugin para correr los tests.

 

  • JBehave: Es uno de los frameworks más grandes escritos para BDD para Java. El proceso de definición de pruebas consiste en escribir las historias, mapearlas en Java, configurarlas y, finalmente, ejecutar las pruebas. El proceso de configuración se hace solo una vez. Asimismo, nos permite asimismo generar informes HTML personalizables usando Freemarker. JBehave es un framework muy flexible; se integra con diferentes lenguajes de programación (Groovy, JRuby, Java), tecnologías y frameworks. Las historias son claras para todo el mundo, y los archivos de mapeo permiten traducirlos fácilmente a Java. La funcionalidad de informes es simplemente genial. La definición de plantillas propias con Freemarker facilita la adopción de cualquier estándar. La configuración de JBehave es un poco compleja, pero solo hace falta hacerla una vez.

 

  • Cucumber: es un framework muy potente para pruebas BDD. Al igual que JBehave tiene muchas funcionalidades útiles, como “test by example” o parámetros para modular las pruebas. Las funcionalidades y el “glue code” son elegantes y pueden mantenerse fácilmente. Cucumber fue escrito originalmente para Ruby. Luego se agregaron plugins y runners adicionales para varias tecnologías (como Java o .Net). Tiene una configuración mucho más simple que JBehave y al igual que este, el proceso de definición de pruebas se divide en: escribir historias, mapearlas en Java (también llamado “glue code”), ejecutar y generar informes. Tiene soporte de Arquillian (http://arquillian.org) de fábrica y asimismo existe un plugin de Jenkins muy útil para generar informes.

 

  • Concordion: Concordion es muy similar a Cucumber, con soporte para múltiples lenguajes y plataformas. Es la implementación más personalizable para describir escenarios. Pero a diferencia de Cucumber, tiene disponibles pocos plugins y es más limitado.

 

JBehave

JBehave soporta desarrollo basado en Java. Usaremos Gherkin para definir las historias de usuario. La historia se compone de uno o más escenarios, y un escenario se compone de uno o más pasos.

Lo mismo que en otras herramientas BDD, hay tres tipos de pasos o steps: ‘Given’, ‘When’, y ‘Then’.

En el caso de JBehave los conceptos clave (y por tanto palabras clave) son: ‘Scenario’, ‘GivenStories’, ‘Given’, ‘When’, ‘Then’, ‘And’

Un escenario típico consistirá de:

  • Given una precondición
  • When un evento ocurra
  • Then la salida a capturar

Cada step en el escenario se corresponderá a una anotación JBehave:

  • @Given: inicializar el contexto
  • @When: hacer la acción
  • @Then: testar la salida esperada

 

Dependencias maven

Necesitaremos la dependencia jbehave-core en nuestro pom:

<dependency>

    <groupId>org.jbehave</groupId>

    <artifactId>jbehave-core</artifactId>

    <version>4.1</version>

    <scope>test</scope>

</dependency>

 

Proceso a seguir

  1. Escribir una historia de usuario
  2. Asignar steps de la historia de usuario al código Java (glue)
  3. Configurar las historias de usuario
  4. Ejecutar las pruebas JBehave
  5. Revisar los resultados

 

1. La historia

Testaremos la siguiente historia sencilla: “Como usuario, me gustaría aumentar un contador de likes, de modo que pueda aumentar el valor del contador en 1“.

Podemos definir la historia en un archivo .story:

  • Scenario: cuando un usuario incremente un contador, su valor se incrementa en 1
  • Given un contador
  • And el contador tiene cualquier valor entero
  • When el usuario incremente el contador
  • Then el valor del contador debe ser 1 entero mayor que el valor previo

 

2. Mapeando los steps

Implementaremos los steps en Java (Recuerda que el valor en las anotaciones debe coincidir exactamente con la descripción.).

 

public class IncreaseSteps {

private int counter;

private int previousValue;

 

@Given(“un contador”)

public void aCounter() {

}

 

@Given(“el contador tiene cualquier valor entero “)

public void counterHasAnyIntegralValue() {

counter = new Random().nextInt();

previousValue = counter;

}

 

@When(“el usuario incremente el contador “)

public void increasesTheCounter() {

counter++;

}

 

@Then(“el valor del contador debe ser 1 entero mayor que el valor previo “)

public void theValueOfTheCounterMustBe1Greater() {

assertTrue(1 == counter – previousValue);

}

}

 

3. Configurando nuestra historia

Para implementar los pasos, tenemos que configurar el escenario para nuestra historia:

 

public class IncreaseStoryLiveTest extends JUnitStories {

 

@Override

public Configuration configuration() {

return new MostUsefulConfiguration()

.useStoryLoader(new LoadFromClasspath(this.getClass()))

.useStoryReporterBuilder(new StoryReporterBuilder()

.withCodeLocation(codeLocationFromClass(this.getClass()))

.withFormats(CONSOLE));

}

 

@Override

public InjectableStepsFactory stepsFactory() {

return new InstanceStepsFactory(configuration(), new IncreaseSteps());

}

 

@Override

protected List<String> storyPaths() {

return Arrays.asList(“increase.story”);

}

 

}

 

En storyPaths(), proporcionamos nuestra ruta de archivo .story para ser analizada por JBehave.

La implementación de los steps reales se proporciona en stepsFactory(). Luego, en configuration(), se configuran el loader de la historia y el informe de historia.

En este punto, tenemos todo listo y podemos lanzar nuestra historia simplemente ejecutando:

mvn clean test

 

4. Revisando los resultados del testing

Podemos ver el resultado de nuestra prueba en la consola. Como nuestras pruebas han pasado con éxito, la salida sería la misma con nuestra historia:

 

  • Scenario: cuando un usuario incremente un contador, su valor se incrementa en 1
  • Given un contador
  • And el contador tiene cualquier valor entero
  • When el usuario incremente el contador
  • Then el valor del contador debe ser 1 entero mayor que el valor previo

 

Si no hemos implementado un paso del escenario, el informe nos avisará. Por ejemplo si no implementamos el paso @When:

 

  • Scenario: cuando un usuario incremente un contador, su valor se incrementa en 1
  • Given un contador
  • And el contador tiene cualquier valor entero
  • When el usuario incremente el contador (PENDING)
  • Then el valor del contador debe ser 1 entero mayor que el valor previo (NOT PERFORMED)

 

El informe indicará @When un paso esté pendiente, y debido a eso, el paso @Then no se ejecuta.
Si hemos tenido un error de ejecución en el Then:

 

  • Scenario: cuando un usuario incremente un contador, su valor se incrementa en 1
  • Given un contador
  • And el contador tiene cualquier valor entero
  • When el usuario incremente el contador
  • Then el valor del contador debe ser 1 entero mayor que el valor previo (FAILED)
  • (java.lang.AssertionError)

 

Detalles sobre el mapeo de historias

El mapeo se hace usando expresiones regulares de forma predeterminada. El mismo texto debe usarse en las historias y anotaciones (también puede estar vinculado a variables).

Cuando JBehave no encuentra el mapeo correspondiente, imprime un mensaje de advertencia. Este mensaje contiene también métodos de plantillas que podrían copiarse en clases de mapeo. Esto puede ayudar a acelerar la implementación.

Otra buena funcionalidad es la anotación @Pending: los pasos anotados con ella simplemente se omiten. Esto nos puede servir en el proceso de implementación en contextos de pasos “no implementados” o “en progreso”.

 

Reflexiones finales

Tenemos disponibles muchos frameworks Behavior-Driven Development (BDD) para Java. JDave y EasyB sirven para escenarios sencillos. Para proyectos más sofisticados y con lógica de negocio más compleja JBehave y Cucumber son los recomendables.

JBehave es una excelente opción para Java que nos permite definir escenarios a partir de historias y generar unas pruebas muy completas y flexibles que cumplan con el paradigma BDD. Aunque presenta un poco de complejidad en la configuración, el trabajo paga con creces el esfuerzo inicial en los subsiguientes pasos del proceso. Asimismo JBehave nos permite generar informes HTML bastante customizables usando Freemarker. Además se puede integrar fácilmente con JUnit y con otras herramientas de reporting como Serenity para automatizar la aceptación de testing.

 


Entradas relacionadas

Cursos relacionados
Nuestro sitio utiliza cookies para análisis. Si no estás seguro de ello, echa un vistazo a nuestra política de privacidad.