Especificando e testando em Java com BDD através do Spock
Saiba como praticar o BDD (Behavior-Driven Development) utilizando o Spock como framework de especificações e testes em seus projetos.
A adoção de metodologias ágeis, como Extreme Programming (XP), Scrum e Kanban, reposiciona e redimensiona o teste a uma das atividades fundamentais no desenvolvimento de software, não só pela garantia de qualidade do produto final, mas também para a própria especificação do mesmo. Para melhor definir e suportar essa atividade foram sendo criadas novas práticas e métodos, das quais podemos destacar o TDD, ATDD e o BDD. Esses, por sua vez, impulsionaram o nascimento de frameworks de testes como o JUnit, RSpec, Cucumber e o Spock, sobre o qual discorremos aqui.
O Spock é um framework de especificação e testes para Java e Groovy. Através dele podemos aplicar em nosso desenvolvimento conceitos, notação e estilos do BDD, que, como será visto, definem requisitos de sistema de forma concisa, expressiva e bastante legível, mesmo para não programadores, através de especificações e cenários.
Neste artigo veremos como o Spock pode ser aplicado no desenvolvimento e teste de software utilizando um projeto para uma aplicação web composto de serviços REST que fornecem informações geoestatísticas de regiões, estados e municípios do Brasil a partir de dados do IBGE. Em sua implementação utilizaremos o Spring, mais especificamente o Spring Boot, como tecnologia base e o Maven como ferramenta de building e gerenciamento de dependências. Dessa forma, também exploraremos como o Spock pode ser naturalmente integrado tanto à fase de testes do Maven quanto aos recursos de testes do Spring.
Contudo, antes de abordarmos o desenvolvimento, vamos entender melhor o que se quer dizer com concisão, expressividade e legibilidade de testes, conforme mencionado anteriormente, para melhor avaliar o legado do BDD e do Spock. Para isso, vamos relembrar a necessidade, função e evolução do teste no desenvolvimento de software em Java, desde os simples unitários até as práticas de desenvolvimento orientado a testes, como o TDD, ATDD e o próprio BDD.
Testes unitários, integrados e o JUnit
Desde sempre houve a necessidade de se testar no desenvolvimento de software, seja em Java ou qualquer outra linguagem/ambiente. Testes visam assegurar que determinado requisito esteja implementado conforme o esperado após o desenvolvimento. Além disso, eles não precisam ser, necessariamente, artefatos construídos por desenvolvedores, podendo ser formulados e conduzidos por, ou com o auxílio, de uma equipe de testes. Neste artigo, entretanto, abordaremos o teste como uma das responsabilidades do desenvolvedor, o qual pode cumpri-la das seguintes formas:
- Escrevendo testes ad hoc, ou seja, da forma e onde lhe parecer apropriado, o que em Java costuma resultar em um main() escrito na própria classe que se quer testar;
- Escrevendo classes de teste que podem ser executadas de maneira automatizada a qualquer momento com a ajuda de um framework de testes como o JUnit e uma ferramenta de building, como o Ant, Maven, Gradle, entre outras.
Testes ad hoc atendem única e exclusivamente a necessidades pontuais de asserção de qualidade do desenvolvedor que os escreve, e não há como automatizá-los de uma forma simples. Para ilustrar, vamos imaginar que para implementar o requisito “fornecer um texto com a data e hora no formato DD/MM/YYYY HH:MM:SS”, tenha sido criada a classe Clock como apresentada na Listagem 1.
Listagem 1. Código da classe Clock.
01 package br.com.devmedia.jm.woki.ibgez.misc;
02
03 import java.text.SimpleDateFormat;
04 import java.util.Date;
05 import java.util.Locale;
06
07 public final class Clock {
08 private Clock() {
09 // util
10 }
11
12 public static final String DATEFORMAT = "dd/MM/yyyy HH:mm:ss";
13
14 public static String now() {
15 return new SimpleDateFormat(DATEFORMAT, Locale.getDefault()).format(new Date());
16 }
17 }
Um teste ad hoc para o método Clock.now() poderia se resumir à inserção de um main() na classe, como mostra a Listagem 2.
Listagem 2. Código da classe Clock com um teste ad hoc.
01 public final class Clock {
02 ...
03 public static void main(String[] args) {
04 System.out.println(Clock.now());
05 }
06 }
Note que o método de asserção do desenvolvedor foi simplesmente checar se o resultado de System.out.println() corresponde ao esperado, ou seja, o teste é um artifício feito em tempo de desenvolvimento para ser executado manualmente — e essa é a natureza do teste ad hoc.
Agora, para ilustrar um teste utilizando o JUnit, observemos a classe de teste da Listagem 3.
Listagem 3. Uma classe de teste com JUnit para Clock.
01 package br.com.devmedia.jm.woki.ibgez.misc;
02
03 import org.junit.Assert;
04 import org.junit.Test;
05
06 import java.text.DateFormat;
07 import java.text.SimpleDateFormat;
08 import java.util.Date;
09 import java.util.Locale;
10
11 public class ClockTest {
12
13 @Test
14 public void testNow() throws Exception {
15 DateFormat format = new SimpleDateFormat(Clock.DATEFORMAT, Locale.getDefault());
16 String nowStr = Clock.now();
17 // aferir se o retorno de Clock.now() pode ser convertido em um Date,
18 // caso contrário haverá um ParseException e o teste falha
19 Date now = format.parse(nowStr);
20 // assertNotNull() aqui e redundante em termos de assercao, mas melhora a compreensao
21 Assert.assertNotNull(now);
22 Assert.assertThat(nowStr, RegexMatcher.matches(
23 "^\\d/\\d/\\d \\d:\\d:\\d$"));
24 }
25 }
"
[...] continue lendo...
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo