TDD ( Test Driven Development )

TDD

O Test Driven Development (TDD), ou Desenvolvimento Orientado a Testes, é uma técnica fundamental do eXtreme Programming (XP), concebida por Kent Beck. Esta abordagem é enfatizada em “TDD by Example” (Beck, 2002) e promove a criação de testes automatizados antes do desenvolvimento do código. O XP, delineado em “eXtreme Programming Explained” (Beck, 1999), é uma metodologia que inclui práticas como programação pareada e TDD, visando adaptabilidade e qualidade no software. TDD e XP, oriundos dos trabalhos de Beck, se complementam, combinando qualidade desde o início do desenvolvimento com um framework para agilidade e eficiência.

Vantagens e desvantagens

O artigo de 2023 Test Driven Development and Its impact on Program Design and Software Quality: A Systematic Literature Review concluiu que o TDD oferece benefícios significativos, como melhor cobertura de testes e aumento da produtividade.

Vantagens

  • Código fácil de se testar: como o código é constantemente validado por testes, as pessoas programadoras têm confiança para refatorar o código sem medo de introduzir erros. Além disso, ao escrever testes antes de implementar um novo código, a pessoa programadora se concentra na API e no comportamento esperado. Isso ajuda a detectar problemas de design e requisitos antes mesmo da implementação.
  • Funcionalidades bem testadas: cada teste escrito no TDD é uma afirmação do comportamento esperado de uma funcionalidade. Isso significa que, antes mesmo de implementar a funcionalidade, a pessoa programadora deve ter uma compreensão clara de como a funcionalidade deverá se comportar.

Desvantagens

  • Dificuldade para começar: há uma curva de aprendizado associada ao TDD. Entender os princípios do TDD, como escrever testes eficazes e como integrar essa prática no fluxo de trabalho diário, pode levar tempo.
  • Aumento inicial no tempo de desenvolvimento: no início, pode parecer que o TDD aumenta o tempo necessário para desenvolver funcionalidades, pois os testes devem ser escritos antes da implementação do código de produção. Isso pode ser percebido como uma desvantagem em situações em que a velocidade de entrega é a principal prioridade.

Processo

O TDD funciona baseado em ciclos, como na imagem abaixo: Ciclo TDD: Red, Green, Refactor

  • 1º passo: Ao pegar algo novo para desenvolver, após entender os requisitos, faça os testes mesmo antes da implementação. Apesar de ainda não existirem classes e funções, esses testes fornecem uma noção do fluxo e falharão, já que nada foi implementado.
func TestBinarySearch(t *testing.T) {
  arr := []int{-1, 1, 10, 22, 66, 67, 91, 100, 105, 320}
  searchElement := 100
  searchElementIndex := 7


  index := BinarySearch(arr, searchElement)

  if index == -1 {
    t.Error("err")
  }

  if index != searchElementIndex {
    t.Error("Expected index to be ", searchElementIndex, " but got ", index)
  }
}

Código não compilando por não encontrar a função BinarySearch

  • 2º passo: Agora, no segundo passo, é a hora de criar as partes faltantes e fazer o teste passar.

Fazendo o código referente ao teste

func BinarySearch(arr []int, item int) int {
  lo := 0
  hi := len(arr) - 1
  for lo <= hi {
    mid := lo + ((hi - lo)/2)
    shoot := arr[mid]
    if shoot == item {
      return mid
    } else if shoot < item {
      lo = mid + 1
    } else {
      hi = mid - 1
    }
  }

  return -1
}

Agora o código compila e o teste passa

  • 3º passo: Neste passo, é a hora de refatorar e reiniciar o ciclo se necessário.

Refatorando o teste

func TestBinarySearch(t *testing.T) {
  arr := []int{-1, 1, 10, 22, 66, 67, 91, 100, 105, 320}
  searchElement := 100
  searchElementIndex := 7


  index, err := BinarySearch(arr, searchElement)

  if err != nil {
    t.Error("err")
  }

  if index != searchElementIndex {
    t.Error("Expected index to be ", searchElementIndex, " but got ", index)
  }
}

O teste falha, pois não existe o erro no código ainda

Arrumando o código

func BinarySearch(arr []int, item int) (int, error) {
  lo := 0
  hi := len(arr) - 1
  for lo <= hi {
    mid := lo + ((hi - lo)/2)
    shoot := arr[mid]
    if shoot == item {
      return mid, nil
    } else if shoot < item {
      lo = mid + 1
    } else {
      hi = mid - 1
    }
  }

  return -1, errors.New("item was not found")
}

O teste continua passando depois da refatoração

Conclusão

Para concluir, o TDD é uma maneira importante de desenvolver software, focando em testes desde o começo. Apesar de no início parecer mais lento e ter uma curva de aprendizado, os resultados são um código de melhor qualidade e mais fácil de manter. O TDD é um ótimo aliado para quem trabalha com métodos ágeis e quer garantir um trabalho de qualidade.

E aí, o que você acha do TDD? Já usou ou tem vontade de experimentar? Compartilhe suas experiências e opiniões nos comentários!

Referências