Probar en la pista de Elixir

Aprende a probar tus ejercicios de Elixir en Exercism


Desde la terminal, cambia al directorio base del ejercicio y luego ejecuta las pruebas con:

$ mix test

Esto ejecutará el archivo de pruebas que se encuentra en la subcarpeta test, un archivo que termina en _test.exs.

Pruebas pendientes

En las suites de pruebas de los ejercicios de práctica, todas las pruebas excepto la primera están marcadas para omitirse.

Una vez que logres que pase una prueba, puedes habilitar la siguiente comentando el @tag :pending correspondiente con el símbolo #.

Por ejemplo:

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

Si quieres ejecutar todas las pruebas a la vez, puedes incluir todas las pruebas omitidas usando la opción --include en el comando mix test:

$ mix test --include pending

O puedes habilitar todas las pruebas comentando la línea ExUnit.configure en la suite de pruebas.

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

Funcionalidades adicionales de las pruebas de Elixir

ExUnit y mix test ofrecen bastantes métodos para agrupar, etiquetar y ejecutar pruebas, además de varias formas de controlar la ejecución de las pruebas, gran parte de lo cual se resume a continuación.

Métodos para ejecutar pruebas específicas

Documentación:

Ejecutar las pruebas de un archivo específico

Todas las pruebas de un solo archivo se pueden ejecutar con mix test especificando el archivo:

$ mix test test/<FILE>.exs

NOTA: el tagging puede afectar cuáles pruebas se ejecutan realmente con este método.

Ejecutar pruebas individuales

Las pruebas individuales se pueden ejecutar haciendo referencia al número de línea de una prueba en el archivo:

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

Se pueden ejecutar varias pruebas indicando varios números de línea separados por :.

Por ejemplo, dado un archivo con el siguiente contenido con números de línea:

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

La 1ª y la 3ª prueba se pueden ejecutar con:

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

NOTA: cuando especificas pruebas mediante números de línea, el tagging se ignora.

Ejecutar grupos de pruebas

Las pruebas se pueden agrupar usando describe:

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

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

Todas las pruebas de un grupo se pueden ejecutar haciendo referencia a su número de línea en el archivo, igual que cuando haces referencia a pruebas individuales y las ejecutas.

Documentación:

Otras opciones útiles de mix test

  • --include y --exclude: ejecutan o no pruebas específicas según sus @tag
  • --failed: ejecuta solo las pruebas que fallaron la última vez que se ejecutaron
  • --max-failures: la suite deja de evaluar pruebas cuando se alcanza ese número de fallos
  • --seed: establece la semilla del generador de números aleatorios que se usa para aleatorizar el orden de las pruebas. --seed 0 desactiva la aleatorización, de modo que las pruebas de un solo archivo siempre se ejecutarán en el mismo orden en que se definieron
  • --stale: ejecuta solo las pruebas que hacen referencia a módulos que cambiaron desde la última vez que se ejecutaron las pruebas con --stale
  • --only task_id:1 (o con otro número): en los ejercicios de aprendizaje, ejecuta solo las pruebas asociadas a esa tarea específica

Documentación:

Typespecs y Dialyzer (DIscrepancy AnalYZer for ERlang programs)

Los ejercicios de Elixir incluyen un archivo de implementación esqueleto en la subcarpeta lib. Este archivo describe el módulo y las funciones que se espera que implementes. En la mayoría de los ejercicios, encontrarás typespecs arriba de la declaración de la función. Estas comienzan con la etiqueta @spec y normalmente siguen el formato @spec function_name(type1, type2) :: return_type. Se usan en Elixir y Erlang como documentación y junto con una herramienta llamada Dialyzer para encontrar inconsistencias de tipos y posibles bugs. Para más información, consulta la documentación de typespecs. Para la documentación sobre Dialyzer, consulta Erlang -- dialyzer.

De manera opcional, quizá quieras revisar los tipos de tu implementación con Dialyzer. Para eso tendrás que dar un par de pasos. Para lograrlo, debes agregar la dependencia Dialyxir al archivo mix.exs de tu problema.

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

Luego usa las tareas de mix para obtener y compilar desde la línea de comandos:

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

Si es la primera vez que ejecutas Dialyzer, lo más probable es que no tengas un archivo plt. Dialyzer usa la tabla de búsqueda persistente, o PLT, para almacenar en caché información sobre los tipos integrados de Elixir y Erlang. Para crear un plt con valores predeterminados razonables, ejecuta:

$ mix dialyzer --plt

Por último, puedes ejecutarlo con:

$ mix dialyzer

Asegúrate de cambiar la ruta por la ruta de tu sistema a las bibliotecas de Elixir. Por ejemplo, si instalaste Elixir con homebrew, probablemente lo encuentres en /usr/local/Cellar/elixir/1.3.2.

Cabe reiterar que ejecutar Dialyzer y eliminar todas las advertencias es un paso opcional al completar un ejercicio. Las advertencias de Dialyzer pueden ser difíciles de descifrar. Por ejemplo, examina las advertencias de esta implementación bastante absurda del ejercicio Bob.

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

  def hey(input) do
  end
end

Esto produce las siguientes advertencias.

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()

La primera advertencia significa que la función no devuelve el tipo correcto. La última indica que la segunda definición de la función nunca se puede alcanzar porque la primera siempre coincide.