Início > Java > BDD em Java na prática, com JBehave

BDD em Java na prática, com JBehave


Venho estudando algumas coisas relacionadas a Behaviour-Driven Development (BDD) e tenho gostado bastante de algumas características dessa metodologia.

Na prática pretendo mostrar, de maneira simplória, um exempço de como tenho utilizado em minhas explorações e algumas referências importantes para quem está iniciando nesta prática.

Primeiramente, vamos a um pouco de conceito:

O BDD é uma das técnicas ágeis para desenvolvimento de software que encoraja a colaboração entre os participantes de um projeto de software à medida que estes podem trabalhar juntos desenvolvendo user stories que poderão ser executadas.

Como não vou entrar em detalhes sobre a técnica em si, recomendo fortemente a leitura do post introdutório (e de outras coisas interessantes) direto do blog do Dan North, o pai da criança.

Foi ele também o criador do primeiro framework para trabalho com esta técnica – o JBehave.

Atualmente existem diversas ferramentas que apóiam BDD em diversas linguagens (como  RSpecJBehaveJSSpecNSpec). Aqui, irei utilizar o JBehave.

Uma pequena introdução

O JBehave pode ser baixado aqui e é de fácil configuração. Basta copiar os jars para o claspath da aplicação.

O JBehave trabalha com cenários, mais ou menos como este (retirado do site do JBehave):

Given I am not logged in
When I log in as Liz with a password JBehaver
Then I should see a message, “Welcome, Liz!”

Onde:

“Given” é a condição inicial
“When” é a ação realizada para a obtenção do resultado
“Then” a conclusão/comportamento esperado

Os cenários são salvos em um arquivo texto e para cada cenário, precisamos de uma classe que defina os passos (extendendo Steps) e outra para definir o cenário (extendendo Scenario).

A classe que representa o cenário será executada como um teste JUnit e apresentará os resultados com as famosas “barras verdes” (como um JUnit test mesmo). Para isso, esta classe precisa, em seu construtor, adicionar cada Step criado para o cenário.

Um outro ponto importante é que o nome da classe deve ter relacionamento com o nome do arquivo que contém a descrição do cenário.

Exemplo:
para um cenário “user_logs_in_successfully”
a classe que o representará deve ser “UserLogsInSuccessfully”, trocando os “_” por o camel casing;

Vamos ao exemplo

O exemplo que irei apresentar é bem básico (ridículo) e servirá apenas para introduzir a técnica. Precisamos preencher um pedido com um produto, informando seu nome e quantidade e o pedido será fechado apenas se a quantidade informada estiver disponível em estoque.

A user story poderia ser definida como: “Como um usuário, desejo preencher um pedido com objetivo de gerar uma venda de determinado produto”

Seguindo o padrão de stories sugerido por Mike Cohn (e também encorajado pelo próprio Dan North), nosso cenário poderia ser algo como:

Title Preenchimento de Pedido

Narrative:
As a Usuario
I want Preencher um pedido
So that Finalizar uma venda

Scenario: Verificar o saldo de produtos
Given O estoque tem 10 produtos
When Eu verifico que há a disponibilidade para vender 5 produtos
Then Deve retornar “true”

Scenario: Pedido preenchido com sucesso
Given O estoque tem 10 produtos
When Eu preencho um pedido com 3 produtos
Then Deve ser retornado que o status de preenchimento do pedido é “true”

Darei a este arquivo o nome “pedido_preenchido” . Agora, criarei a classe Java que representará o cenário acima.


package tests.jbehave.java.estoquedisponivel;

public class PedidoPreenchido extends Scenario {
 public PedidoPreenchido (){
}

}

Neste momento já posso rodar minha classe e ver o resultado da execução. Como estou criando este exemplo com o Eclipse e já tenho o JUnit configurado, simplesmente rodo a classe como um “JUnit Test”.

Rodando a classe como um JUnit test

Rodando a classe como um JUnit test

O resultado da execução de PedidoPreenchido indica, claro, que a implementação dos passos ainda não foi realizada (pending).

Resultado da execução

Resultado da execução

Vamos agora a criação das classes Step, dando vida a nossa especificação de user story.

Iniciaremos com a classe responsável pelo primeiro cenário:

import static org.jbehave.Ensure.ensureThat;
import org.jbehave.scenario.annotations.Given;
import org.jbehave.scenario.annotations.Then;
import org.jbehave.scenario.annotations.When;
import org.jbehave.scenario.steps.Steps;
import tests.easymock.Estoque;

public class EstoqueDisponivelSteps extends Steps {

Estoque estoque = new Estoque();
Boolean resultado =false;

@Given("O estoque tem $quant produtos")
public void preencherEstoque(Integer quant) {
   estoque.setQuantidade(quant);
}

@When("Eu verifico que há a disponibilidade para vender $quant produtos")
public void verifDisponibilidade(Integer quant) {
  resultado = estoque.quantDisponivel(quant);
}

@Then("Deve retornar \"$retorno\"")
public void checarResultado(String retorno) {
  ensureThat(resultado.toString().equals(retorno));
}

}

Repare que as anotações Given, When e Then precisam ter o mesmo texto que foi utilizado no cenário (retirando as plavras Given, When e Then).
Neste momento, nosso compilador reclamaria por ainda não termos implementado a classe Estoque. Segue o código desta classe:

public class Estoque {
	
	private Integer quantidade = 10;

	public Integer getQuantidade() {
		return quantidade;
	}

	public void setQuantidade(Integer quantidade) {
		this.quantidade = quantidade;
	}
	
	public boolean quantDisponivel(Integer quant){
		
		if (quant <= quantidade){
			return true;
		}else{
			return false;
		}
	}

Agora, precisamos adicionar este step à nossa classe PedidoPreenchido.

import org.jbehave.scenario.Scenario;

public class PedidoPreenchido extends Scenario {
	
	public PedidoPreenchido(){
		addSteps(new EstoqueDisponivelSteps());
	}

}

Ao executá-la novamente, obtemos o resultado a seguir:

Resultado da execução após implementação do Step

Resultado da execução após implementação do Step

Repare que o primeiro cenário (“Verificar saldo de Proutos”) não aparece mais como PENDING e resta apenas o segundo cenário. Isto indica que o primeiro cenário foi executado com sucesso.

Vamos introduzir um erro neste cenário e ver o resultado. Alterando o trecho “Given O estoque tem 10 produtos” para “Given O estoque tem 0 produtos”, recebemos o resultado a seguir, após a execução.

Resultado da execução, com erro

Resultado da execução, com erro

Repare que o cenário volta a aparecer, agora com a indicação de falha (FAILED) devido ao erro que inserimos. Ou seja, o comportamento foi diferente do esperado.

No painel do JUnit podemos observar a indicação da falha:

Painel do JUnit apresentando o problema

Painel do JUnit apresentando o problema

Por fim, resta a implementação do segundo cenário (“Pedido preenchido com sucesso”), mas não há nada que altere drasticamente o funcionamento. Assim, não irei complementar isso por aqui.

Como devem ter percebido, acabamos misturando inglês e português para escrever os cenários. Particularmente, acho isso horrível.

Para resolver este problema, o Emerson Macedo publicou um post onde fala sobre a criação de uma biblioteca para possibilitar a escrita dos cenários em português. Sugiro que leiam.

Os comportamentos que testei aqui são pequenos (como testes unitários que poderiam ter sido feitos utilizando TDD), mas geralmente os comportamentos podem ser testados de forma mais ampla (de fora para dentro, incluindo a interface), utilizando algum framework como o Selenium para interação com a interface, mas isso é coisa para outro post.

Bom, fico por aqui e até a próxima.

A[]´s

  1. 29/11/2010 às 18:52

    Muito interessante e revolucionária essa forma de desenvolvimento.

  2. Danilo
    30/11/2010 às 13:16

    muito interessante, uma coisa que sempre me perguntava e ainda não havia tentato me responder como era esses testes de software.

  3. 24/04/2013 às 20:54

    Hi to every one, for the reason that I am in fact eager of reading this weblog’s post to be updated regularly. It includes nice stuff.

  1. 30/01/2010 às 09:02
  2. 03/01/2011 às 14:56

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: