【问题标题】:Why does Eunit not require test functions to be exported?为什么 Eunit 不需要导出测试函数?
【发布时间】:2016-07-14 05:57:57
【问题描述】:

我正在阅读 Learn You Some Erlang 中的 EUnit 章节,我从所有代码示例中注意到的一件事是测试函数从未在 -export() 子句中声明。

为什么 EUnit 能够选择这些测试功能?

【问题讨论】:

    标签: erlang eunit


    【解决方案1】:

    很高兴我找到了这个问题,因为它为我提供了一种有意义的拖延方式,我想知道函数是如何动态创建和导出的。

    首先查看 Erlang/OTP Github 存储库中影响 EUnit 的最新提交,即4273cbd。 (这样做的唯一原因是为了找到一个相对稳定的anchor而不是git分支。)

    0。包含EUnit的头文件

    根据EUnit's User's Guide,第一步是在测试模块中-include_lib("eunit/include/eunit.hrl").,所以我认为这就是魔法发生的地方。

    1。 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.
    

    1.1-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} 编译选项,那么 M 的所有函数和属性都可以通过使用 Module:parse_transform/2 的实现来迭代。它的第一个参数是Forms,这是Erlang的abstract format中描述的M的模块声明(在Erlang Run-Time System Application (ERTS) User's Guide中描述。

    2。 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 提供)构建一个模块声明。在line 82 上,它会注入EUnit documentation 中提到的test/0 函数。

    【讨论】:

      【解决方案2】:

      From the documentation:

      在 Erlang 模块中使用 EUnit 的最简单方法是在模块开头添加以下行(在 -module 声明之后,但在任何函数定义之前):

      -include_lib("eunit/include/eunit.hrl").
      

      这将产生以下效果:

      • 创建一个导出函数 test()(除非测试被关闭,并且模块还没有包含 test() 函数),它可用于运行定义的所有单元测试模块

      • 导致名称匹配的所有函数 ..._test()..._test_() 从模块中自动导出(除非关闭测试,或 EUNIT_NOAUTO 宏已定义)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-20
        • 2012-05-24
        • 2011-12-27
        • 1970-01-01
        • 2018-07-02
        • 1970-01-01
        • 1970-01-01
        • 2023-03-16
        相关资源
        最近更新 更多