Cucumber y Java - definiendo test de una manera amigable

Cucumber es un framework que permite definir test para nuestras aplicaciones de una manera verbal. Es decir definir los test con frases entendibles, de forma que cualquier persona que quiera realizar un test no necesite saber programar ya que los definira en texto plano.

Para que te hagas una idea, esto bastaria para definir un test con cucumber:

Feature: Probar calculadora
  Mediante este test voy a
  hacer pruebas con dos numeros a
  ver como se comporta mi aplicacion.

  Scenario: Sumatorio de dos numeros
    Given dos numeros 2,3
    When sumo los dos numeros
    And multiplico el resultado por 3
    Then resultado debe ser 15

Feature es el nombre de la funcionalidad que queramos, y debajo ponemos la descripcion que queramos.
Luego definimos un Scenario, podemos definir tantos como queramos para nuestras pruebas.En este caso creo Sumatorio de dos numeros porque es lo que voy a probar.
Vemos que tenemos palabras claves (Given, When, And, Then) que definen los distintos pasos del test. (Muy parecido a lo que hace JUnit). Estas palabras veremos que tienen relacion directa con anotaciones en nuestro codigo.
Nuestro test va a consistir en :
Definimos que dados 2 numeros (parametros de entrada 2 y 3), los sumo luego los multiplico por 3 y el resultado debe ser 15.
¿facil y entendible, no? ;-DD

Vamos a generar un proyecto con maven y a integrar este test:

1.Generar un proyecto de maven :
        mvn archetype:create -DgroupId=org.dppware.cucumber -DartifactId=CucumberTest

        *Voy a editar con Eclipse, asi que mvn eclipse:eclipse para generar el .project y .classpath

         Nos quedara algo asi: 



2. Editamos el pom.xml para meter la dependencias de cucumber. Tambien especificamos nivel de compilacion y algun parametro para surefire-repors y definimos donde se encuentras los resource que se deben buscar en los test. Quedara algo asi:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.dppware.cucumber</groupId>
  <artifactId>CucumberTest</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>CucumberTest</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cucumber.jvm.version>1.0.2</cucumber.jvm.version>
  </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-core</artifactId>
            <version>${cucumber.jvm.version}</version>
        </dependency>
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>${cucumber.jvm.version}</version>
        </dependency>
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>${cucumber.jvm.version}</version>
        </dependency>
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-html</artifactId>
            <version>0.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.1</version>
        </dependency>
    </dependencies>

    <build>
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
            </testResource>
        </testResources>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.11</version>
                <configuration>
                    <testFailureIgnore>true</testFailureIgnore>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

      


3.Creamos la clase test/java/org/dppware/cucumber/CucumberTest.java con este contenido


En Cucumber.options le estamos definiendo que queremos que nos saque los resultados de una forma mas bonita en un html, que encontraremos en la carpeta target/cucumber. Tambien se puede añadir la opcion monochrome=true, que sacara las trazas en color,etc...

@Cucumber.Options(format = {"pretty", "html:target/cucumber"},monochrome = true)


4.Creamos un archivo miPrimerTest.feature . Los archivos feature es donde definimos los test que vimos arriba. Creamos este archivo dentro de test/resources/org/dppware/cucumber/miPrimerTest.feature


El contenido del archivo es el que pusimos arriba:

 Feature: Probar calculadora
  Mediante este test voy a
  hacer pruebas con dos numeros a
  ver como se comporta mi aplicacion.

  Scenario: Sumatorio de dos numeros
    Given dos numeros 2,3
    When sumo los dos numeros
    And multiplico el resultado por 3
    Then resultado debe ser 15





5.Ahora que ya hemos definido el test en el feature, pues vamos a preparar el codigo que se ejecutara. Creamos una clase en test/java/org/dppware/cucumber/CucumberTest.java

Con este contenido:

Si nos fijamos mediante expresiones regulares  asociamos las anotaciones de .features con el codigo que lo ejecutara. Ademas, vemos como desde la definicion del test este inyectara los valores para hacer el test. Es decir, por ejemplo este paso:

Given dos numeros 2,3
esta relacionado con 
 @Given("^dos numeros (\\d+),(\\d+)$")
    public void given_dos_numeros(int x, int y) {


Los valores 2 y 3 deben ser numericos , de ahi la restriccion rexExp (\\d+) , (\\d+) y vemos como el metodo acepta los 2 argumentos que seran inyectados.

Lo mismo pasa con el ultimo metodo para hacer el Assert del resultado esperado

Then resultado debe ser 15
@Then("^resultado debe ser (\\d+)$")
    public void resultado_debe_ser(int x) {
               Assert.assertEquals(x,summatory);
    }

 *Nota, aunque los nombres de los metodos, se parecen a las expresiones regulares, no hace falta que sean iguales.

6. Antes de ejecutar el test, vamos a definir otro Scenario, para probar un test que va bien y otro que va mal (por ejemplo que el resultado sea 16). Al final el .feature quedara asi:

Feature: Probar calculadora
  Mediante este test voy a
  hacer pruebas con dos numeros a
  ver como se comporta mi aplicacion.

  Scenario: Sumatorio de dos numeros
    Given dos numeros 2,3
    When sumo los dos numeros
    And multiplico el resultado por 3
    Then resultado debe ser 15
   
  Scenario: Sumatorio de dos numeros
    Given dos numeros 2,3
    When sumo los dos numeros
    And multiplico el resultado por 3
    Then resultado debe ser 16


7.Si ejecutamos los test, o hacemos clean install de la aplicacion veremos que en las trazas pone que un Scenario fue bien y el otro mal.

Si entramos en la ruta donde genera los reports, es decir en target/cucumber vemos un index.html (que especificamos cuando definimos la anotacion @Cucumber.Options(format = {"pretty", "html:target/cucumber"})  y ahi podemos ver el resultado y nos saca que uno fue bien y otro mal:


Cucumber es una herramienta muy potente para definir test y que nos puede ayudar a hacer TDD de una manera sencilla y agil. Tambien nos permite que una vez definidao el codigo de la prueba, cualquier persona pueda definir sus propios test sin necesidad de conocer el codigo y testear nuestra aplicacion con otras variantes.

El codigo fuente de este ejemplillo que he hecho lo puedes descargar desde aqui:
https://www.dropbox.com/s/hhoqe2a4geemces/CucumberTest.rar


Rock!

Enlaces:
En esta pagina hay ejemplos de como integrar las pruebas de Cucumber con Selenium y hacer pruebas simuladas de Navegador.:  http://www.coveros.com/blog/cucumber-jvm-setup

ACTUALIZACIONES:
He estado investigando un poco mas y hay otra version mas nueva de cucumber-jvm , la 1.1.2

    <properties>
        <cucumber.jvm.version>1.1.2</cucumber.jvm.version>
    </properties>

Y para generar los reports en html tambien hay otra version
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-html</artifactId>
            <version>0.2.2</version>
        </dependency>
Esta dependencia genera unos reports en html que en Chrome funcionan perfectamente.
Incluso en nuestro codigo podemos usar
@Before
    public void init(Scenario scenario) throws Exception {
        //Scenario Reference
        setScenario(scenario);
      
    }

y con el objeto cucumber.api.Scenario  con su metodo .write(String msg) podemos sacar trazas de nuestra ejecucion que luego se podran ver en el reporte HTML en chrome (en firefox no carga bien, quizas es mi version de Firefox...:-( )

getScenario().write("aqui trazo lo que quiero....");


Cuando compileis vereis que las clases han cambiado la estructura de paquetes, con lo cual en las clases basta con cambiar los imports por estos:
import cucumber.api.Scenario;
import cucumber.api.java.Before;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;



Comentarios

  1. Muchas gracias Daniel. He podido comprender e interiorizar el uso y la potencia de Cucumber gracias a este post.

    Un saludo.

    ResponderEliminar
  2. Excelente muchas gracias, tienes bastante talento ��

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

Reiniciar usuario de SVN Subversion

Subir campos Blob a BBDD (Oracle) con Java

Persistencia con EclipseLink 2.0