Testes na trilha de Elixir

Aprenda a testar seus exercícios de Elixir no Exercism


No terminal, mude para o diretório base do exercício e execute os testes com:

$ mix test

Isso vai executar o arquivo de teste encontrado na subpasta test, um arquivo com final _test.exs

Testes pendentes

Nas suítes de testes dos exercícios de prática, todos os testes, exceto o primeiro, foram marcados para serem ignorados.

Assim que um teste passar, você pode ativar o próximo teste comentando o @tag :pending correspondente com um símbolo #.

Por exemplo:

# @tag :pending
test "shouting" do
  assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end

Se você quiser rodar todos os testes de uma vez, pode incluir todos os testes ignorados usando a flag --include no comando mix test:

$ mix test --include pending

Ou você pode ativar todos os testes comentando a linha ExUnit.configure na suíte de testes.

# ExUnit.configure exclude: :pending, trace: true

Recursos adicionais de teste do Elixir

ExUnit e mix test oferecem várias formas de agrupar, marcar e executar testes, além de vários métodos para controlar a execução dos testes, muitos dos quais são resumidos abaixo.

Métodos para executar testes específicos

Documentação:

Executando testes em um arquivo específico

Todos os testes de um único arquivo podem ser executados via mix test especificando o arquivo:

$ mix test test/<FILE>.exs

OBSERVAÇÃO: o tagging pode afetar quais testes são realmente executados usando este método.

Executando testes individuais

Testes individuais podem ser executados referenciando o número da linha do teste no arquivo:

$ mix test test/<FILE>.exs:LINENUM

Vários testes podem ser executados informando vários números de linha separados por :.

Por exemplo, dado um arquivo com o conteúdo a seguir com números de linha:

test "Test 1" do           # 1
  # test implementation    # 2-6
end                        # 7
                           # 8
test "Test 2" do           # 9
  # test implementation    # 10-21
end                        # 22
                           # 23
test "Test 3" do           # 24
  # test implementation    # 25-35
end                        # 36

Os 1º e 3º testes podem ser executados com:

$ mix test test/FILE.exs:1:24

OBSERVAÇÃO: ao especificar testes por números de linha, o tagging é ignorado.

Executando grupos de testes

Os testes podem ser agrupados usando describe:

describe "short test group description" do
  test "test description" do
    # test implementation
  end

  test "another test description" do
    # test implementation
  end
end

Todos os testes de um grupo podem ser executados referenciando o número da linha do grupo no arquivo, assim como referenciar e executar testes individuais.

Documentação:

Outras opções úteis do mix test

  • --include e --exclude - executa ou não testes específicos com base em suas @tags
  • --failed - executa apenas os testes que falharam na última execução
  • --max-failures - a suíte para de avaliar testes quando esse número de falhas é atingido
  • --seed - define a semente do gerador de números aleatórios usado para randomizar a ordem dos testes. --seed 0 desativa a randomização, então os testes de um único arquivo sempre serão executados na mesma ordem em que foram definidos
  • --stale - executa apenas os testes que referenciam módulos que mudaram desde a última vez que os testes foram executados com --stale
  • --only task_id:1 - ou com outro número, em exercícios de aprendizagem executa apenas os testes associados à tarefa específica

Documentação:

Typespecs e Dialyzer (DIscrepancy AnalYZer for ERlang programs)

Os exercícios de Elixir incluem um arquivo de implementação esqueleto na subpasta lib. Esse arquivo descreve o módulo e as funções que você deve implementar. Na maioria dos exercícios, você encontrará typespecs acima da declaração da função. Eles começam com a tag @spec e normalmente seguem o formato @spec function_name(type1, type2) :: return_type. Eles são usados em Elixir e Erlang como documentação e em conjunto com uma ferramenta chamada Dialyzer para encontrar inconsistências de tipo e possíveis bugs. Para mais informações, veja a documentação de typespecs. Para documentação sobre o Dialyzer, veja Erlang -- dialyzer.

Opcionalmente, você pode querer verificar os tipos da sua implementação com o Dialyzer. Há alguns passos que você precisará seguir. Para fazer isso, você precisa adicionar a dependência Dialyxir ao arquivo mix.exs do seu exercício.

defp deps do
  # Add this:
  [{:dialyxir, "~> 0.4", only: [:dev]}]
end

Depois, use tarefas do mix para baixar e compilar pela linha de comando:

$ mix deps.get
...
$ mix deps.compile
...

Se esta for a primeira vez que você executa o Dialyzer, provavelmente não terá um arquivo plt. A tabela de consulta persistente, ou PLT, é usada pelo Dialyzer para armazenar em cache informações sobre tipos internos de Elixir e Erlang. Para criar um plt com padrões razoáveis, execute:

$ mix dialyzer --plt

Por fim, ele pode ser executado com:

$ mix dialyzer

Certifique-se de ajustar o caminho para o caminho das bibliotecas do Elixir no seu sistema. Por exemplo, se você instalou o Elixir com o Homebrew, provavelmente vai encontrá-lo em /usr/local/Cellar/elixir/1.3.2.

Vale repetir que executar o Dialyzer e remover todos os avisos é um passo opcional ao concluir um exercício. Os avisos do Dialyzer podem ser difíceis de decifrar. Por exemplo, examine os avisos desta implementação bem boba do exercício Bob.

defmodule Bob do
  @spec hey(input :: String.t()) :: String.t()
  def hey(input) do
    1
  end

  def hey(input) do
  end
end

Isso produz os seguintes avisos.

bob.exs:2: Invalid type specification for function 'Elixir.Bob':hey/1. The success typing is (_) -> 1
bob.exs:7: The variable _input@1 can never match since previous clauses completely covered the type any()

O primeiro aviso significa que a função não está retornando o tipo correto. O último indica que a segunda definição da função nunca pode ser alcançada porque a primeira definição da função sempre corresponde.