Lerne, wie du deine Elixir-Übungen auf Exercism testest
Wechsle im Terminal in das Basisverzeichnis der Übung und führe die Tests dann so aus:
$ mix test
Damit wird die Testdatei im Unterordner test ausgeführt, also eine Datei, die auf _test.exs endet.
In den Testsuiten von Übungen sind alle Tests bis auf den ersten als übersprungen markiert.
Sobald ein Test durchläuft, kannst du den nächsten wieder aktivieren, indem du das jeweilige @tag :pending mit einem # auskommentierst.
Zum Beispiel:
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
Wenn du alle Tests auf einmal ausführen möchtest, kannst du mit der Option --include für den Befehl mix test alle übersprungenen Tests einbeziehen:
$ mix test --include pending
Alternativ kannst du alle Tests aktivieren, indem du die Zeile ExUnit.configure in der Testsuite auskommentierst.
# ExUnit.configure exclude: :pending, trace: true
ExUnit und mix test bieten mehrere Möglichkeiten, Tests zu gruppieren, zu taggen und auszuführen, sowie verschiedene Arten, die Testausführung zu steuern. Das Wichtigste davon ist unten zusammengefasst.
Dokumentation:
Alle Tests einer einzelnen Datei lassen sich über mix test ausführen, indem du die Datei angibst:
$ mix test test/<FILE>.exs
HINWEIS: Das
taggingkann beeinflussen, welche Tests mit dieser Methode tatsächlich ausgeführt werden.
Einzelne Tests lassen sich ausführen, indem du die Zeilennummer eines Tests in der Datei angibst:
$ mix test test/<FILE>.exs:LINENUM
Mehrere Tests lassen sich ausführen, indem du mehrere Zeilennummern durch : getrennt angibst.
Ein Beispiel: Gegeben sei eine Datei mit folgendem Inhalt samt Zeilennummern:
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
Der 1. und der 3. Test lassen sich so ausführen:
$ mix test test/FILE.exs:1:24
HINWEIS: Wenn du Tests über Zeilennummern angibst, wird
taggingignoriert.
Tests lassen sich mit describe gruppieren:
describe "short test group description" do
test "test description" do
# test implementation
end
test "another test description" do
# test implementation
end
end
Alle Tests einer Gruppe lassen sich ausführen, indem du ihre Zeilennummer in der Datei angibst, genau wie beim Angeben und Ausführen einzelner Tests.
Dokumentation:
mix test
--include und --exclude - führen bestimmte Tests anhand ihrer @tags aus oder nicht--failed - führt nur Tests aus, die beim letzten Lauf fehlgeschlagen sind--max-failures - die Testsuite bricht das Auswerten von Tests ab, sobald diese Anzahl an Testfehlern erreicht ist--seed - setzt den Startwert des Zufallszahlengenerators, mit dem die Reihenfolge der Tests zufällig bestimmt wird. --seed 0 schaltet die Zufälligkeit ab, sodass die Tests in einer einzelnen Datei immer in der Reihenfolge ausgeführt werden, in der sie definiert wurden--stale - führt nur Tests aus, die Module referenzieren, die sich seit dem letzten Lauf mit --stale geändert haben--only task_id:1 - oder mit einer anderen Nummer: führt bei Lernübungen nur die Tests aus, die zur jeweiligen Aufgabe gehörenDokumentation:
Elixir-Übungen enthalten im Unterordner lib eine Skelettdatei für die Implementierung. Diese Datei skizziert das Modul und die Funktionen, die du implementieren sollst. In den meisten Übungen findest du Typespecs über der Funktionsdeklaration. Diese beginnen mit dem @spec-Tag und folgen üblicherweise dem Format @spec function_name(type1, type2) :: return_type. Sie dienen in Elixir und Erlang als Dokumentation und werden zusammen mit einem Tool namens Dialyzer genutzt, um Typinkonsistenzen und mögliche Fehler zu finden. Mehr dazu findest du in der Dokumentation zu Typespecs. Dokumentation zu Dialyzer findest du unter Erlang -- dialyzer.
Optional kannst du die Typen deiner Implementierung mit Dialyzer prüfen. Dazu sind ein paar Schritte nötig. Dafür musst du die Abhängigkeit Dialyxir in der Datei mix.exs deiner Übung hinzufügen.
defp deps do
# Add this:
[{:dialyxir, "~> 0.4", only: [:dev]}]
end
Dann nutzt du Mix-Tasks, um sie von der Kommandozeile aus zu holen und zu kompilieren:
$ mix deps.get
...
$ mix deps.compile
...
Wenn du Dialyzer zum ersten Mal ausführst, hast du höchstwahrscheinlich noch keine plt-Datei. Die persistente Nachschlagetabelle, kurz PLT, wird von Dialyzer genutzt, um Informationen über eingebaute Elixir- und Erlang-Typen zwischenzuspeichern. Um eine PLT mit sinnvollen Standardwerten zu erstellen, führe aus:
$ mix dialyzer --plt
Zum Schluss lässt er sich so ausführen:
$ mix dialyzer
Passe den Pfad an den Pfad der Elixir-Bibliotheken auf deinem System an. Wenn du Elixir zum Beispiel mit Homebrew installiert hast, findest du es wahrscheinlich unter /usr/local/Cellar/elixir/1.3.2.
Noch einmal zur Erinnerung: Dialyzer auszuführen und alle Warnungen zu beseitigen, ist beim Lösen einer Übung optional. Dialyzer-Warnungen sind oft schwer zu entschlüsseln. Schau dir zum Beispiel die Warnungen für diese sehr alberne Implementierung der Übung Bob an.
defmodule Bob do
@spec hey(input :: String.t()) :: String.t()
def hey(input) do
1
end
def hey(input) do
end
end
Das erzeugt die folgenden Warnungen.
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()
Die erste Warnung bedeutet, dass die Funktion nicht den richtigen Typ zurückgibt. Die letzte zeigt an, dass die zweite Funktionsdefinition nie erreicht werden kann, weil die erste Funktionsdefinition immer passt.