Мне нужно было научиться писать тесты на OCaml, чтобы я мог контролировать работу своих модулей. Не настолько я крутой программист, чтобы всегда обходиться без тестов, особенно это касается новых для меня языков.
Из списка библиотек для тестирования взял первый по списку - Alcotest. Когда не знаешь ничего, лучший способ разобраться - попробовать.
Для разработки первого теста взял первую задачу из списка 99 problems на ocaml.org - "Write a function last : 'a list -> 'a option that returns the last element of a list".
# last [ "a" ; "b" ; "c" ; "d" ];; - : string option = Some "d" # last [];; - : 'a option = None
Т.е. нужно написать функцию, которая возвращает последний элемент списка или None.
Решение задачи
Чтобы проверить в работе Alcotest, я сперва написал решение задачи. Хоть это и не по канонам TDD, в соответствии с которыми сперва пишут тест, но меня это устраивает.
Интерфейс last.mli
val last: 'a list -> 'a option
Реализация last.ml
let rec last = function | [] -> None | [elem] -> Some elem | hd :: tl -> last tl
Тест test.ml
open Last let empty_list () = Alcotest.(check (option reject)) "Last from empty list" None (last []) let one_elem () = Alcotest.(check (option int)) "Last from empty list" (Some 1) (last [1]) let last_int () = Alcotest.(check (option int)) "Last int" (Some 2) (last [1; 2]) let last_char () = Alcotest.(check (option char)) "Last char" (Some 'a') (last ['b'; 'c'; 'a']) let last_string () = Alcotest.(check (option string)) "Last string" (Some "hi") (last ["bye"; "hi"]) let () = Alcotest.run "Test Last.last function which should return last element of a list" [ "test_set", [ "Get last from empty list", `Quick, empty_list; "Get the only element from list", `Quick, one_elem; "Get the int from list", `Quick, last_int; "Get the char from list", `Quick, last_char; "Get the string from list", `Quick, last_string; ] ]
Сборка
$ ocamlbuild -pkg alcotest test.byte Finished, 7 targets (7 cached) in 00:00:00.
И результат в терминале
$ ./test.byte Testing Test Last.last function which should return last element of a list. [OK] test_set 0 Get last from empty list. [OK] test_set 1 Get the only element from list. [OK] test_set 2 Get the int from list. [OK] test_set 3 Get the char from list. [OK] test_set 4 Get the string from list. The full test results are available in `_tests`. Test Successful in 0.002s. 5 tests run.
Все тесты пройдены, все танцуют.
Эмуляция ошибки
На самом деле нужно было с этого начинать разработку, но не в том случае, если для меня предметом изучения является сама библиотека для тестов.
Сперва я поломал функцию last
let rec last = function | _ -> None
Потом пересобрал тест и запустил
$ ocamlbuild -pkg alcotest test.byte Finished, 7 targets (4 cached) in 00:00:00. $ ./test.byte Testing Test Last.last function which should return last element of a list. [OK] test_set 0 Get last from empty list. [ERROR] test_set 1 Get the only element from list. [ERROR] test_set 2 Get the int from list. [ERROR] test_set 3 Get the char from list. [ERROR] test_set 4 Get the string from list. The full test results are available in `_tests`. 4 errors! in 0.003s. 5 tests run.
Ну и славно, значит ошибки искать тоже умеет. А ещё он умеет раскрашивать вывод.
Заключение
Alcotest на текущий момент меня устраивает, поэтому сейчас буду тестировать свой код при помощи этой библиотеки. Для моих скромных потребностей её хватает.