【问题标题】:Print test fixture description in erlang eunit failure在 erlang eunit failure 中打印测试夹具描述
【发布时间】:2018-06-13 02:16:45
【问题描述】:

有没有办法打印使用夹具的 erlang 测试生成器的测试描述?使用生成器很难判断哪些测试实际上失败了,打印描述会有所帮助。

例子:

-module(math_test).

-include_lib("eunit/include/eunit.hrl").
-define(test(Desc, F), {Desc, {setup, fun setup/0, fun cleanup/1, F}}).

setup() ->
  ok.

cleanup(_) ->
  ok.

math_test_ () ->
  [
    ?test("adds two numbers", fun add_two_numbers/0),
    ?test("subtract two numbers", fun subtract_two_numbers/0),
    ?test("undefined method called", fun undefined_error/0)
  ].

add_two_numbers () ->
  ?assertEqual(2, 1 + 3).

subtract_two_numbers () ->
  ?assertEqual(1, 2 - 2).

undefined_error () ->
  undefined_module:uh_oh().

然后运行它

[root@a7c901c022bb src]# rebar3 eunit --module=math_test
===> Verifying dependencies...
===> Compiling math
===> Performing EUnit tests...
FFF
Failures:

  1) math_test:math_test_/0
     Failure/Error: ?assertEqual(2, 1 + 3)
       expected: 2
            got: 4
     %% /src/_build/test/lib/math/src/math_test.erl:20:in `math_test:-add_two_numbers/0-fun-0-/1`
     Output: 
     Output: 
  2) math_test:math_test_/0
     Failure/Error: ?assertEqual(1, 2 - 2)
       expected: 1
            got: 0
     %% /src/_build/test/lib/math/src/math_test.erl:23:in `math_test:-subtract_two_numbers/0-fun-0-/1`
     Output: 
     Output: 
  3) math_test:math_test_/0
     Failure/Error: {error,undef,[{undefined_module,uh_oh,[],[]}]}
     Output: 

前 2 个错误没有问题,但不是很好——您至少可以在断言中看到实际出错的地方。

然而,第三个错误(调用未定义的模块/方法)是严重错误的地方——没有真正的方法可以判断它来自哪里!

有没有办法改进,比如打印带有失败日志的测试描述?

【问题讨论】:

标签: erlang eunit


【解决方案1】:

您可以做的一件事是将测试描述放在测试本身上,而不是整个setup 元组。也就是改变这一行:

-define(test(Desc, F), {Desc, {setup, fun setup/0, fun cleanup/1, F}}).

到:

-define(test(Desc, F), {setup, fun setup/0, fun cleanup/1, {Desc, F}}).

通过该更改,将打印测试描述:

Failures:

  1) math_test:math_test_/0: adds two numbers
     Failure/Error: ?assertEqual(2, 1 + 3)
       expected: 2
            got: 4
     %% /tmp/math_test/mylib/_build/test/lib/mylib/test/math_test.erl:20:in `math_test:-add_two_numbers/0-fun-0-/0`
     Output: 
     Output: 
  2) math_test:math_test_/0: subtract two numbers
     Failure/Error: ?assertEqual(1, 2 - 2)
       expected: 1
            got: 0
     %% /tmp/math_test/mylib/_build/test/lib/mylib/test/math_test.erl:23:in `math_test:-subtract_two_numbers/0-fun-0-/0`
     Output: 
     Output: 
  3) math_test:math_test_/0: undefined method called
     Failure/Error: {error,undef,[{undefined_module,uh_oh,[],[]}]}
     Output: 

要尝试的另一件事是使用 ?_test 宏而不是普通的 fun 术语指定测试函数:

math_test_ () ->
  [
    ?test("adds two numbers", ?_test(add_two_numbers())),
    ?test("subtract two numbers", ?_test(subtract_two_numbers())),
    ?test("undefined method called", ?_test(undefined_error()))
  ].

?_test 宏会记住它出现的行号,并在测试失败时将其包含在输出中:

  1) math_test:math_test_/0:14: adds two numbers
  [...]
  2) math_test:math_test_/0:15: subtract two numbers
  [...]
  3) math_test:math_test_/0:16: undefined method called
  [...]

现在您可以知道这些测试是从哪一行调用的。


另一种方法是让各个函数返回 eunit “测试对象”,而不是仅仅运行测试。这将涉及使用?_assertEqual 而不是?assertEqual,或者将整个内容包装在?_test 中:

math_test_ () ->
  [
    ?test("adds two numbers", add_two_numbers()),
    ?test("subtract two numbers", subtract_two_numbers()),
    ?test("undefined method called", undefined_error())
  ].

add_two_numbers () ->
  ?_assertEqual(2, 1 + 3).

subtract_two_numbers () ->
  ?_assertEqual(1, 2 - 2).

undefined_error () ->
  ?_test(undefined_module:uh_oh())

然后输出包含行号和各个测试函数的名称:

Failures:

  1) math_test:add_two_numbers/0:20: adds two numbers
     Failure/Error: ?assertEqual(2, 1 + 3)
       expected: 2
            got: 4
     %% /tmp/math_test/mylib/_build/test/lib/mylib/test/math_test.erl:20:in `math_test:-add_two_numbers/0-fun-0-/0`
     Output: 
     Output: 
  2) math_test:subtract_two_numbers/0:23: subtract two numbers
     Failure/Error: ?assertEqual(1, 2 - 2)
       expected: 1
            got: 0
     %% /tmp/math_test/mylib/_build/test/lib/mylib/test/math_test.erl:23:in `math_test:-subtract_two_numbers/0-fun-0-/0`
     Output: 
     Output: 
  3) math_test:undefined_error/0:26: undefined method called
     Failure/Error: {error,undef,[{undefined_module,uh_oh,[],[]}]}
     Output: 

【讨论】:

    【解决方案2】:

    @legoscia 的答案很好,但我也怀疑 rebar3 实现的错误报告对于这种错误来说不是最理想的。使用默认输出直接从 eunit 运行测试,你会得到:

    2> eunit:test(math_test). 
    math_test: math_test_...*failed*
    in function math_test:'-add_two_numbers/0-fun-0-'/0 (math_test.erl, line 22)
    **error:{assertEqual,[{module,math_test},
                          {line,22},
                          {expression,"1 + 3"},
                          {expected,2},
                          {value,4}]}
      output:<<"">>
    
    math_test: math_test_...*failed*
    in function math_test:'-subtract_two_numbers/0-fun-0-'/0 (math_test.erl, line 25)
    **error:{assertEqual,[{module,math_test},
                          {line,25},
                          {expression,"2 - 2"},
                          {expected,1},
                          {value,0}]}
      output:<<"">>
    
    math_test: math_test_...*failed*
    in function undefined_module:uh_oh/0
      called as uh_oh()
    **error:undef 
      output:<<"">>
    
    =======================================================
      Failed: 3.  Skipped: 0.  Passed: 0.
    

    使用“详细”选项,它还会在每次设置之前打印说明。此外,将描述移至测试乐趣,并使用 ?_test(...) 宏创建比普通乐趣更多的位置信息的测试乐趣,正如@legoscia 建议的那样,您会得到以下输出:

      math_test:18: math_test_ (undefined method called)...*failed*
    in function undefined_module:uh_oh/0
      called as uh_oh()
    **error:undef 
      output:<<"">>
    

    您可以将此情况报告给 rebar3 维护人员。

    【讨论】:

      猜你喜欢
      • 2012-06-17
      • 2017-03-05
      • 2014-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多