Kata e TDD: um exemplo prático

Nas artes marciais, um kata é um conjunto preciso de movimentos que simula um lado de um combate. O bjetivo de um kata é atingir a perfeição, é treinar a mente e o corpo para agir em uma situação real particular, de forma que os movimentos perfeitos se tornem automáticos e esteja a disposição quando o praticante precisar.

Um kata de programação é parecido com um kata de artes marciais, mas substituímos os movimentos de combate por movimentos com teclas e mouse, simulando a resolução de um problema. Muito provavelmente você já tenha se deparado com um kata antes, mas não tenha o encarado como tal. Durante a graduação, por exemplo, temos muitos exercícios, a finalidade destes exercícios é colocarmos em prática a teoria aprendida a fim de solucionar problemas. No fundo, a prática de exercícios é um kata.

Katas de programação são muito utilizados para o aprendizado de TDD, pois a técnica de TDD guia a resolução do problema por meio de pequenos passos incrementais que devem ter os testes escritos antes. Solucionar um kata utilizando TDD é muito mais fácil além de ser uma abordagem natural.

Um kata de programação é um problema a ser solucionado. Você pode solucionar o problema da maneira que quiser, não importa a linguagem. O importante é treinar a sua prática e raciocínio na resolução de problemas. Veremos agora um exemplo de kata e uma possível forma de resolvê-lo.

Prática: Kata Calculadora de String

A calculadora de string deve receber números em uma string e retornar a soma desses números. Há mais detalhes e requisitos nessa calculadora, a descrição original deste kata segue abaixo.

  1. Crie uma simples calculadora de strings com o método int add(string numbers) – O método pode receber 0, 1 ou 2 números e retorna a soma destes números (para uma string vazia retorne 0) por exemplo “” ou “1” ou “1,2”
  1. Permita ao método int add(string numbers) receber qualquer quantidade de números
  2. Permita ao método int add(string numbers) aceitar novas linhas.- A seguinte entrada é válida:  “1\n2,3”  (soma sera igual 6)
    – A seguinte entrada é invalida:  “1,\n”

Podemos resolver este kata utilizando TDD. Ao invés de pensarmos em uma solução completa e tentar codificá-la de uma vez, podemos pensar nessa calculadora como tendo vários pequenos problemas para resolver e, então, criar pequenos casos de teste que solucionam cada um dos pequenos problemas da calculadora.

Pensando desta forma, criamos um caso de teste para uma String vazia.

package calculator;

import junit.framework.TestCase;

public class StringCalculatorTest extends TestCase {

	private StringCalculator sCalc;

	protected void setUp() throws Exception {
		sCalc = new StringCalculator();
	}

	public void testStringCalculatorEmptyString() throws Exception {
		assertEquals(0, sCalc.add(""));
	}
}

Criamos primeiro o caso de teste, perceba que ainda não criamos a classe StringCalculator e desta forma o nosso caso de teste não compila. Isso é TDD! Agora vamos fazer o nosso teste passar, para isso temos que criar a classe StringCalculator e implementar o método add(String numbers).

package calculator;

import java.util.StringTokenizer;

public class StringCalculator {

	public int add(String numbers) {		
		return 0;
	}

}

Agora o nosso caso de teste compila, além disso, ele é executado sem erros. Logicamente que a implementação do nosso método add(String numbers) é muito ruim, ele apenas retorna 0. Mas estamos aplicando TDD, o importante é fazer o teste ser executado sem erro, pois temos mais casos de teste para implementar. A ideia é implementar casos de teste e ir refatorando o código até que se atinja o objetivo de uma forma elegante.

O próximo passo é criar um novo caso de teste, desta vez testando uma string com um número.

package calculator;

import junit.framework.TestCase;

public class StringCalculatorTest extends TestCase {

	private StringCalculator sCalc;

	protected void setUp() throws Exception {
		sCalc = new StringCalculator();
	}

	public void testStringCalculatorEmptyString() throws Exception {
		assertEquals(0, sCalc.add(""));
	}

public void testStringCalculatorZero() throws Exception {
		assertEquals(0, sCalc.add("0"));
	}
}

Adicionamos o teste testStringCalculatorZero(), que testa o método add(String numbers) com o número zero. Ao executarmos nosso teste ele passa sem problemas, pois 0 é esperado e o método retorna zero! Que ótimo, podemos continuar! Vamos criar mais um teste, desta vez para o número 1.

package calculator;

import junit.framework.TestCase;

public class StringCalculatorTest extends TestCase {

	private StringCalculator sCalc;

	protected void setUp() throws Exception {
		sCalc = new StringCalculator();
	}

	public void testStringCalculatorEmptyString() throws Exception {
		assertEquals(0, sCalc.add(""));
	}

public void testStringCalculatorZero() throws Exception {
		assertEquals(0, sCalc.add("0"));
	}

public void testStringCalculatorOne() throws Exception {
		assertEquals(1, sCalc.add("1"));
	}

}

Adicionamos agora o teste testStringCalculatorOne(), que testa o método add(String numbers) com o número um. Ao executarmos nosso teste, ele falha, pois ao passarmos o número 1 como parâmetro, é esperado que o retorno seja 1, mas foi zero! Vamos ter que refatorar o nosso código para ele passar neste teste.

package calculator;

import java.util.StringTokenizer;

public class StringCalculator {

	public int add(String numbers) {

		if(numbers.isEmpty()) {
			return 0;
		}

		int number = Integer.valueOf(numbers);

		if(number == 1) {
			return 1;
		} else {
			return 0;
		}
	}
}

Veja que mudamos bastante o nosso código. Agora testamos se a String é vazia, se for retornamos 0. Depois transformamos o valor da String em um int e verificamos se é 1, se for, retornamos 1, senão, retornamos 0. Executamos o nosso teste e ele passa! É claro que essa implementação não é a melhor e nem a mais elegante, mas TDD nos possibilita criar o código de forma incremental e refatorar a cada teste. É interessante notar que mudamos muito o código e ainda assim ele passou em todos os testes, isso é um benefício do desenvolvimento guiado por testes, podemos verificar rapidamente que nossas mudanças não afetam em nada o comportamento esperado pelo código.

Este foi um exemplo de como um kata pode ser resolvido. Termine este kata e melhore o seu código. 🙂

A versão original deste kata, em inglês, está disponível em: http://osherove.com/tdd-kata-1/

Mais sobre kata em: http://codekata.pragprog.com/

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *