I'm going through the EUnit chapter in Learn You Some Erlang and one thing I am noticing from all the code samples is the test functions are never declared in -export()
clauses.
Why is EUnit able to pick these test functions up?
I'm going through the EUnit chapter in Learn You Some Erlang and one thing I am noticing from all the code samples is the test functions are never declared in -export()
clauses.
Why is EUnit able to pick these test functions up?
从文档中:
在 Erlang 模块中使用 EUnit 的最简单方法是在模块的开头添加以下行(在
-module
声明之后,但在任何函数定义之前):-include_lib("eunit/include/eunit.hrl").
这将产生以下效果:
创建一个导出函数
test()
(除非关闭了测试,并且模块还没有包含 test() 函数),该函数可用于运行模块中定义的所有单元测试导致名称匹配
..._test()
或..._test_()
从模块中自动导出的所有函数(除非关闭测试,或EUNIT_NOAUTO
定义宏)
很高兴我找到了这个问题,因为它给了我一种有意义的拖延方式,我想知道函数是如何动态创建和导出的。
首先查看 Erlang/OTP Github 存储库中影响 EUnit 的最新提交,即4273cbd。(这样做的唯一原因是找到一个相对稳定的锚点而不是 git 分支。)
根据EUnit's User's Guide,第一步是-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)手册页。
编译(3):
{parse_transform,Module}
使解析转换函数 Module:parse_transform/2 在检查代码错误之前应用于已解析的代码。
从erl_id_trans
模块:
该模块执行 Erlang 代码的身份解析转换。它是作为示例供想要编写自己的解析转换器的用户使用的。如果将选项
{parse_transform,Module}
传递给编译器,parse_transform/2
则编译器会在检查代码是否有错误之前调用用户编写的函数。
基本上,如果模块 M 包含{parse_transform, Module}
compile 选项,那么 M 的所有函数和属性都可以通过使用您的Module:parse_transform/2
. 它的第一个参数是Forms
,它是以 Erlang 的抽象格式描述的 M 的模块声明(在Erlang Run-Time System Application (ERTS) User's Guide中描述。
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
作为第一个参数给出)和要导出的函数列表(由form/5
上面提供)构建一个模块声明。在第 82 行,它注入了EUnit 文档test/0
中提到的函数。