Я просматриваю главу EUnit в Изучите Erlang и кое-что хочу Из всех примеров кода я заметил, что тестовые функции никогда не объявляются в предложениях -export()
.
Почему EUnit поддерживает эти тестовые функции?
Я просматриваю главу EUnit в Изучите Erlang и кое-что хочу Из всех примеров кода я заметил, что тестовые функции никогда не объявляются в предложениях -export()
.
Почему EUnit поддерживает эти тестовые функции?
Самый простой способ использовать EUnit в модуле Erlang — добавить следующую строку в начало модуля (после объявления
-module
, но перед любыми определениями функций):-include_lib("eunit/include/eunit.hrl").
Это будет иметь следующий эффект:
Создает экспортированную функцию
test()
(если тестирование не отключено и модуль еще не содержит функцию test()), которую можно использовать для запуска всех модульных тестов, определенных в модуле.Заставляет все функции, имена которых соответствуют
..._test()
или..._test_()
, автоматически экспортироваться из модуля (если не отключено тестирование или не определен макросEUNIT_NOAUTO
).
Рад, что нашел этот вопрос, потому что он дает мне осмысленный способ откладывать, и мне было интересно, как функции создаются и экспортируются динамически.
Начал с просмотра последнего коммита, затрагивающего EUnit, в репозитории Erlang/OTP Github, который называется 4273cbd а>. (Единственной причиной этого было найти относительно стабильный якорь вместо веток git.)
Согласно Руководству пользователя EUnit, первым шагом будет -include_lib("eunit/include/eunit.hrl").
в тестируемом модуле: поэтому я предполагаю, что именно здесь происходит волшебство.
otp/lib/eunit/include/eunit.hrl
(строки 79–91). )%% Parse transforms for automatic exporting/stripping of test functions.
%% (Note that although automatic stripping is convenient, it will make
%% the code dependent on this header file and the eunit_striptests
%% module for compilation, even when testing is switched off! Using
%% -ifdef(EUNIT) around all test code makes the program more portable.)
-ifndef(EUNIT_NOAUTO).
-ifndef(NOTEST).
-compile({parse_transform, eunit_autoexport}).
-else.
-compile({parse_transform, eunit_striptests}).
-endif.
-endif.
-compile({parse_transform, eunit_autoexport}).
?Из главы «Модуль» Справочного руководства по Erlang (Предопределенные атрибуты модуля< /а>):
-compile(Options).
Опции компилятора. Опции — это одна опция или список опций. Этот атрибут добавляется в список опций при компиляции модуля. См. страницу руководства compile(3) в компиляторе.
Переходим к compile(3):
{parse_transform,Module}
Заставляет функцию преобразования синтаксического анализа Module:parse_transform/2 применяться к анализируемому коду перед проверкой кода на наличие ошибок.
Из модуля erl_id_trans
:
Этот модуль выполняет преобразование синтаксического анализа кода Erlang. Он включен в качестве примера для пользователей, которые хотят написать свои собственные преобразователи синтаксического анализа. Если параметр
{parse_transform,Module}
передается компилятору, перед проверкой кода на наличие ошибок компилятор вызывает написанную пользователем функциюparse_transform/2
.
По сути, если модуль M включает параметр компиляции {parse_transform, Module}
, то все функции и атрибуты M можно повторить с помощью вашей реализации Module:parse_transform/2
. Его первый аргумент — Forms
, это объявление модуля M, описанное в абстрактном формате< /strong> (описано в пользовательском приложении Erlang Run-Time System (ERTS)). Руководство.
otp/lib/eunit/src/eunit_autoexport.erl
Этот модуль экспортирует только parse_transfrom/2
для соответствия параметру компиляции {parse_transform, Module}
, и его первая задача — выяснить, какие суффиксы настроены для функций и генераторов тестовых случаев. Если не задано вручную, используйте _test
и _test_
соответственно (через lib/eunit/src/eunit_internal.hrl
).
Затем он сканирует все функции и атрибуты вашего модуля, используя eunit_autoexport:form/5
, и создает список экспортируемых функций, где суффиксы выше совпадают (плюс исходные функции. Я могу ошибаться в этом...).
Наконец, eunit_autoexport:rewrite/2
создает модуль декларация из исходного Forms
(передана eunit_autoexport:parse_transform/2
< /a> в качестве первого аргумента) и список экспортируемых функций (который был предоставлен form/5
выше). В строке 82 вставляется test/0
функция, упомянутая в документации EUnit.