DEV Community

Elixir UTFPR (por Adolfo Neto)
Elixir UTFPR (por Adolfo Neto)

Posted on • Updated on

TDD com Elixir

Alt Text
Uma das coisas mais legais em Elixir é a facilidade para criar e executar testes automatizados (testes que são escritos como código).

Com isso, você pode fazer TDD (Test-Driven Development ou Desenvolmento Guiado por Testes) com facilidade. Não sabe o que é TDD? Leia o livro do Maurício Aniche!

O que vou mostrar aqui é o passo-a-passo para fazer TDD em Elixir.

Passo 1: Criar o projeto

Uma vez tendo o Elixir instalado, você vai num terminal (no meu caso, um Ubuntu 20.04 dentro do WSL do Windows 10), e digita mix new <nome do projeto>. No caso abaixo, o nome do projeto é calculadora.

elixir@utfpr:~/DevTo$ mix new calculadora
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/calculadora.ex
* creating test
* creating test/test_helper.exs
* creating test/calculadora_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd calculadora
    mix test

Run "mix help" for more commands.
Enter fullscreen mode Exit fullscreen mode

Pronto. O mix criou a pasta calculadora e dentro desta as pastas lib e test. Ou seja, o mix já separou para você o código que tem funcionalidades (pasta lib) do código de testes (pasta test). Além disso ele criou 5 arquivos. Os arquivos relevantes para nosso exemplo simples são apenas lib/calculadora.ex e test/calculadora_test.exs.

Passo 2 - Rodar os Testes

Veja na imagem acima que o mix sugere que você, logo após a criação do projeto, vá para a pasta do novo projeto, calculadora, e execute os testes. Sim, o mix já cria testes para você.

Vamos primeiro então rodar os testes que o mix criou:

elixir@utfpr:~/DevTo$ cd calculadora
elixir@utfpr:~/DevTo/calculadora$ mix test
Compiling 1 file (.ex)
Generated calculadora app
..

Finished in 0.08 seconds
1 doctest, 1 test, 0 failures

Randomized with seed 652059
elixir@utfpr:~/DevTo/calculadora$
Enter fullscreen mode Exit fullscreen mode

Olha que legal! Passou em todos os testes! OK, só tem dois testes: um doctest e um teste normal.

Passo 3: Remover o doctest

Vamos dar uma espiada nos arquivos gerados? Importante: estou usando o Elixir 1.11.2. Diferentes versões podem ter conteúdos diferentes nos arquivos gerados.

Arquivo lib/calculadora.ex:

defmodule Calculadora do
  @moduledoc """
  Documentation for `Calculadora`.
  """

  @doc """
  Hello world.

  ## Examples

      iex> Calculadora.hello()
      :world

  """
  def hello do
    :world
  end
end

Enter fullscreen mode Exit fullscreen mode

Como aqui estamos tratando do básico, eu vou apagar o doctest, ou seja, tudo que está entre @doc """ e """.

Arquivo lib/calculadora.ex passa a ser:

defmodule Calculadora do
  @moduledoc """
  Documentation for `Calculadora`.
  """

  def hello do
    :world
  end
end

Enter fullscreen mode Exit fullscreen mode

Rodemos os testes de novo:

elixir@utfpr:~/DevTo/calculadora$ mix test
Compiling 1 file (.ex)
.

Finished in 0.03 seconds
1 test, 0 failures

Randomized with seed 900374
elixir@utfpr:~/DevTo/calculadora$
Enter fullscreen mode Exit fullscreen mode

Pronto. Agora só temos um teste.

Passo 4: Escrever o seu primeiro teste

Vamos dar uma olhada no teste? Está em test/calculadora_test.exs.

Isto é importante! O arquivo deve estar na pasta test/ e seu nome deve terminar em _test.exs. Se não for assim, o arquivo contendo os testes não vai ser encontrado pela biblioteca que roda os testes.

Arquivo test/calculadora_test.exs:

defmodule CalculadoraTest do
  use ExUnit.Case
  doctest Calculadora

  test "greets the world" do
    assert Calculadora.hello() == :world
  end
end
Enter fullscreen mode Exit fullscreen mode

Como vemos acima, o teste gerado pelo mix tem descrição "greets the world" (tradução: "cumprimenta o mundo").

O único comando deste teste é um assert. Ele afirma (a tradução do Google Translate para assert) que se eu chamar a função hello() do módulo Calculadora, o resultado vai ser igual (==) ao átomo :world.

O teste que escreveremos simplesmente afirma que 2 + 2 = 4:

  test "2+2 é 4" do
    assert Calculadora.soma(2,2) == 4
  end
Enter fullscreen mode Exit fullscreen mode

Com este teste, o arquivo test/calculadora_test.exs passa a ser:

defmodule CalculadoraTest do
  use ExUnit.Case
  doctest Calculadora

  test "greets the world" do
    assert Calculadora.hello() == :world
  end

  test "2+2 é 4" do
    assert Calculadora.soma(2,2) == 4
  end
end
Enter fullscreen mode Exit fullscreen mode

Uma das práticas de TDD é rodar os testes mesmo quendo você espera que eles falhem, como será o caso abaixo pois sequer criamos a função Calculadora.soma/2.

Rodemos os testes de novo:

elixir@utfpr:~/DevTo/calculadora$ mix test
warning: Calculadora.soma/2 is undefined or private
  test/calculadora_test.exs:10: CalculadoraTest."test 2+2 é 4"/1

.

  1) test 2+2 é 4 (CalculadoraTest)
     test/calculadora_test.exs:9
     ** (UndefinedFunctionError) function Calculadora.soma/2 is undefined or private
     code: assert Calculadora.soma(2,2) == 4
     stacktrace:
       (calculadora 0.1.0) Calculadora.soma(2, 2)
       test/calculadora_test.exs:10: (test)



Finished in 0.3 seconds
2 tests, 1 failure

elixir@utfpr:~/DevTo/calculadora$
Enter fullscreen mode Exit fullscreen mode

Os testes falharam? Ótimo. Era o esperado.

Passo 5: Fazer o teste passar usando Passos de Bebê.

A técnica Passos de Bebê (Baby Steps) sugere que você escreva o mínimo necessário para passar no teste. Neste caso, o mínimo necessário é escrever a função Calculadora.soma/2 ignorando seus parâmetros e retornando 4:

  def soma(_,_), do: 4
Enter fullscreen mode Exit fullscreen mode

Arquivo lib/calculadora.ex passa a ser:

defmodule Calculadora do
  @moduledoc """
  Documentation for `Calculadora`.
  """

  def hello do
    :world
  end

  def soma(_,_), do: 4
end
Enter fullscreen mode Exit fullscreen mode

Rodemos os testes de novo:

elixir@utfpr:~/DevTo/calculadora$ mix test
Compiling 1 file (.ex)
..

Finished in 0.03 seconds
2 tests, 0 failures

Randomized with seed 371832
elixir@utfpr:~/DevTo/calculadora$ 
Enter fullscreen mode Exit fullscreen mode

Passo 6: Escrever o seu segundo teste

O segundo teste que escreveremos afirma que 3 + 3 = 6:

  test "3+3 é 6" do
    assert Calculadora.soma(3,3) == 6
  end
Enter fullscreen mode Exit fullscreen mode

Com este teste, o arquivo test/calculadora_test.exs passa a ser:

defmodule CalculadoraTest do
  use ExUnit.Case
  doctest Calculadora

  test "greets the world" do
    assert Calculadora.hello() == :world
  end

  test "2+2 é 4" do
    assert Calculadora.soma(2,2) == 4
  end

  test "3+3 é 6" do
    assert Calculadora.soma(3,3) == 6
  end
end
Enter fullscreen mode Exit fullscreen mode

Rodemos os testes de novo:

elixir@utfpr:~/DevTo/calculadora$ mix test
..

  1) test 3+3 é 6 (CalculadoraTest)
     test/calculadora_test.exs:13
     Assertion with == failed
     code:  assert Calculadora.soma(3, 3) == 6
     left:  4
     right: 6
     stacktrace:
       test/calculadora_test.exs:14: (test)



Finished in 0.06 seconds
3 tests, 1 failure

Randomized with seed 966924
elixir@utfpr:~/DevTo/calculadora$
Enter fullscreen mode Exit fullscreen mode

Vejam que agora a mensagem de erro é diferente. O teste esperava 6 mas a função retornou 4.

Como fazer o teste passar?
Agora basta implementar de fato a função Calculadora.soma/2:

  def soma(num1, num2), do: num1 + num2
Enter fullscreen mode Exit fullscreen mode

Arquivo lib/calculadora.ex passa a ser:

defmodule Calculadora do
  @moduledoc """
  Documentation for `Calculadora`.
  """

  def hello do
    :world
  end

  def soma(num1, num2), do: num1 + num2
end
Enter fullscreen mode Exit fullscreen mode

Rodemos os testes de novo:

elixir@utfpr:~/DevTo/calculadora$ mix test
Compiling 1 file (.ex)
...

Finished in 0.03 seconds
3 tests, 0 failures

Randomized with seed 498106
elixir@utfpr:~/DevTo/calculadora$
Enter fullscreen mode Exit fullscreen mode

Passou em todos os testes!

OK, acho que por hoje é só. Daqui vocês já podem continuar.

Vejam que não deu tempo de falar de refatoração nem das diversas formas de afirmar/refutar usando ExUnit, o arcabouço (framework) de testes de unidade do Elixir.

E então, o que vocês querem saber mais sobre Elixir?

PS: um vídeo relacionado

Top comments (0)