Vamos implementar o TDD em um projeto pré-configurado, que servirá de guia para o nosso aprendizado. O projeto Guia será um Todo-List (Lista de tarefas). Na imagem abaixo, vemos o Diagrama de Classes do Projeto que possui apenas uma Classe Model (Tarefa) e os Métodos do CRUD, que serão construídos através do TDD:
classDiagram
class Tarefa {
- id : Long
- nome : String
- descricao: String
- responsavel: String
- data: LocalDate
- status: Boolean
+ findAll()
+ findById(Long id)
+ findAllByNome(String nome)
+ post(Tarefa tarefa)
+ put(Tarefa tarefa)
+ delete(Long id)
}
ATENÇÃO: *Estamos implementando o TDD em outro projeto, porquê o Projeto Blog Pessoal já passou pelos testes na Sessão anterior e o projeto já está finalizado. * |
---|
O projeto guia está disponível no link abaixo:
Após acessar o repositório, vamos seguir a sequência de passos abaixo:
- Abra o STS
- Na pasta de qualquer projeto, clique com o botão direito do mouse e na sequência clique na opção: Show in 🡢 System Explorer
- Será aberta a pasta Workspace onde o STS grava os seus projetos.
- Clique com o botão direito do mouse dentro da pasta Workspace (não clique sobre nenhuma pasta de projeto) e clique na opção: Git Bash Here, como mostra a imagem abaixo:
- No Git Bash, execute o comando abaixo para clonar o projeto guia todolist:
git clone https://github.com/rafaelq80/tdd_todolist.git
- Após a clonagem, será criada a pasta todolist dentro da pasta Workspace.
- Antes de continuarmos, precisamos apagar a pasta .git, na pasta todolist, caso contrário não será possível enviar o projeto para o seu Github ao conluir as atividades.
- Abra a pasta todolist e localize a pasta .git
- Caso esta pasta não esteja sendo exibida, na janela do Windows Explorer, clique na Guia Exibir e na sequência no botão Opções. Na janela Opções de Pasta, na Guia Modo de Exibição, no item Configurações avançadas, localize a opção: Pastas e arquivos ocultos e marque a opção Mostrar arquivos, pastas e unidades ocultas (como mostra a figura abaixo). Em seguida clique em OK para concluir.
- Apague a pasta .git
- No STS, importe o projeto todolist, através do menu File 🡢 Import
- Será aberta a janela Import. Clique na opção Maven 🡢 Existing Maven Projects, como mostra a figura abaixo e clique no botão Next.
- Na janela Import Maven Projects, clique no botão Browse... e selecione a pasta todolist, como mostra a figura abaixo e clique no botão Finish para concluir.
- Na imagem abaixo, você confere o Projeto todolist após ser importado para o STS.
- Observe que o projeto já está todo configurado para criar testes.
Vamos criar o nosso primeiro teste, seguindo modelo TDD:
Antes de criarmos a Classe, vamos criar em src/test/java o pacote controller:
-
No lado esquerdo superior, na Guia Package explorer, clique com o botão direito do mouse sobre a Package com.generation.todolist, na Source Folder src/test/java e clique na opção New 🡪 Package.
-
Na janela New Java Package, no item Name, acrescente no final do nome da Package .controller, como mostra a figura abaixo:
Na sequência, vamos criar a Classe TarefaControllerTest, que será utilizada para testar a Classe Controladora TarefaController. Crie a Classe TarefaControllerTest na package controller, na Source Folder de Testes (src/test/java)
-
No lado esquerdo superior, na Guia Package Explorer, clique com o botão direito do mouse sobre a Package com.generation.todolist.controller, na Source Folder src/test/java e clique na opção New 🡪 Class.
-
Na janela New Java Class, no item Name, informe o nome da Classe que será o mesmo nome da Classe Principal (TarefaController) + a palavra Test, para indicar que se trata de uma Classe de Testes, ou seja, TarefaControllerTest, como mostra a figura abaixo:
- Implemente o código abaixo na Classe TarefaControllerTest. Na implementação abaixo vamos criar o Método de teste Criar tarefa:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TarefaControllerTest {
@Autowired
private TestRestTemplate testRestTemplate;
@Test
@DisplayName("Criar nova Tarefa")
public void deveCriarNovaTarefa() throws Exception {
Tarefa tarefa = new Tarefa(0L, "Tarefa 01", "Tarefa numero 1", "João", LocalDate.now(), true);
HttpEntity<Tarefa> corpoRequisicao = new HttpEntity<Tarefa>(tarefa);
ResponseEntity<Tarefa> resposta = testRestTemplate
.exchange("/tarefas", HttpMethod.POST, corpoRequisicao, Tarefa.class);
assertEquals(HttpStatus.CREATED, resposta.getStatusCode());
assertEquals(corpoRequisicao.getBody().getNome(), resposta.getBody().getNome());
}
}
-
Para executar o Teste, na Guia Package Explorer, no pacote src/test/java, clique com o botão direito do mouse sobre a Classe TarefaControllerTest e clique na opção Run As 🡪 JUnit Test.
-
Acompanhe o resultado do teste, ao lado da Guia Project Explorer, na Guia JUnit.
- Observe que o teste falhou, porquê a Classe TarefaController ainda não foi criada.
- Vamos criar a Classe TarefaController na Source folder Principal (src/main/java), no pacote com.generation.todolist.controller e implemente o código abaixo:
@RestController
@RequestMapping("/tarefas")
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class TarefaController {
@Autowired
private TarefaRepository tarefaRepository;
@PostMapping
public ResponseEntity<Tarefa> post(@Valid @RequestBody Tarefa tarefa){
return ResponseEntity.status(HttpStatus.CREATED).body(tarefaRepository.save(tarefa));
}
}
- Execute o Teste novamente e observe que desta vez ele passou!
- Observe que na implementação do Método post(Tarefa tarefa), foi feito o mínimo para passar o teste e o código não precisa de melhorias no momento.
Vamos implementar o Método de teste Listar tarefas por id, na Classe TarefaControllerTest, seguindo o modelo TDD:
- Implemente o Método deveListarApenasUmaTarefa(), na Classe TarefaControllerTest, logo abaixo do Método deveCriarNovaTarefa():
@Test
@DisplayName("Listar uma Tarefa Específica")
public void deveListarApenasUmaTarefa() {
Tarefa buscaTarefa = tarefaRepository.save(new Tarefa(0L, "Tarefa 02", "Tarefa numero 2",
"Maria", LocalDate.now(), true));
ResponseEntity<String> resposta = testRestTemplate
.exchange("/tarefas/" + buscaTarefa.getId(), HttpMethod.GET, null, String.class);
assertEquals(HttpStatus.OK, resposta.getStatusCode());
}
-
Para executar o Teste, na Guia Package Explorer, no pacote src/test/java, clique com o botão direito do mouse sobre a Classe TarefaControllerTest e clique na opção Run As 🡪 JUnit Test.
-
Acompanhe o resultado do teste, ao lado da Guia Project Explorer, na Guia JUnit.
- Observe que o teste falhou, porquê o Método findById(Long id) ainda não foi implementado na Classe TarefaController.
- Vamos criar o Método findById(Long id) na Classe TarefaController, logo abaixo do Método post(Tarefa tarefa):
@GetMapping("/{id}")
public ResponseEntity<Optional<Tarefa>> getById(@PathVariable Long id) {
Optional <Tarefa> buscaTarefa = tarefaRepository.findById(id);
if(buscaTarefa.isPresent())
return ResponseEntity.ok(buscaTarefa);
else
return ResponseEntity.notFound().build();
}
- Execute o Teste novamente e observe que desta vez ele passou!
- Observe que na implementação do Método findById(Long id), foi feito o mínimo para passar o teste, entretanto nesta implementação o código pode ser melhorado, ou seja, Refatorado. Esta implementação está muito grande (verbosa) e pode ficar mais limpa.
- Vamos refatorar o Método findById(Long id) utilizando uma Expressão Lambda em conjunto com o Optional map, como mostra o código abaixo:
@GetMapping("/{id}")
public ResponseEntity<Tarefa> getById(@PathVariable Long id) {
return tarefaRepository.findById(id)
.map(resposta -> ResponseEntity.ok(resposta))
.orElse(ResponseEntity.notFound().build());
}
- Execute o Teste novamente e observe que ele continua passando!
- Neste teste vimos o processo completo do Ciclo do TDD.
No link abaixo, você confere o projeto completo, finalizado.