我正在浏览Learn You Some Erlang中的EUnit章节,我从所有代码示例中注意到的一件事是测试函数永远不会在-export()
子句中声明。
为什么EUnit能够选择这些测试功能?
答案 0 :(得分:2)
在Erlang模块中使用EUnit的最简单方法是在模块的开头添加以下行(在
-module
声明之后,但在任何函数定义之前):-include_lib("eunit/include/eunit.hrl").
这将产生以下效果:
创建导出的函数
test()
(除非测试已关闭,模块尚未包含test()函数),可用于运行所有模块中定义的单元测试导致名称匹配
..._test()
或..._test_()
的所有功能自动从模块中导出(除非测试已关闭) ,或定义了EUNIT_NOAUTO
宏)
答案 1 :(得分:0)
很高兴我发现了这个问题,因为它为我提供了一种有意义的拖延方式,我想知道如何动态创建和导出函数。
首先在4273cbd的Erlang / OTP Github存储库中查看影响EUnit的最新提交。 (这样做的唯一原因是找到一个相对稳定的锚点,而不是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参考手册》的“模块”一章(Pre-Defined Module Attributes):
-compile(Options).
编译器选项。选项是单个选项或选项列表。该属性在以下情况下添加到选项列表中: 编译模块。请参见Compiler中的 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}
编译选项,则可以通过使用Module:parse_transform/2
的实现来迭代M的所有功能和属性。它的第一个参数是Forms
,它是Erlang的abstract format(在Erlang Run-Time System Application (ERTS) User's Guide中描述的M的模块声明。
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
)和要导出的功能列表(由{{ 1}})。在line 82上注入EUnit documentation中提到的form/5
函数。