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.
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$
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
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
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$
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
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
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
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$
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
Arquivo lib/calculadora.ex passa a ser:
defmodule Calculadora do
@moduledoc """
Documentation for `Calculadora`.
"""
def hello do
:world
end
def soma(_,_), do: 4
end
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$
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
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
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$
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
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
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$
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)