使用eunit编写Erlang单元测试的最佳实践/约定

时间:2011-06-23 05:22:56

标签: unit-testing erlang

我目前正在学习Erlang,并且想知道单元测试的一些好的做法或惯例是什么?我目前正在使用eunit。

构思这个问题:

  • 我目前正在为每个函数编写一个单元测试模块,这样我的测试名称非常简单,并采用了should_do_desired_behaviour_test()的形式。

  • 我开始为我正在编写的每个模块使用一个模块,但感觉不对,因为命名测试变得越来越笨重,并且测试模块感觉杂乱无章。

  • 我所采用的方法预见的问题是,我最终会得到许多需要执行的模块。然后,我将需要某种全局模块来运行每个测试模块中的所有测试。

所以我想我不太确定采取什么方法,或者我是否正确地走上正轨。你通常如何管理单元测试?

干杯。

2 个答案:

答案 0 :(得分:24)

迄今为止最常见的方法是每个应用程序模块一个测试模块。如果您正确命名模块,EUnit将为您找到并运行所有测试,无需创建运行测试的全局模块。例如,给定:

  • 的src /
    • meck.erl
    • meck_mod.erl
  • 测试/
    • meck_tests.erl
    • meck_mod_tests.erl

如果您运行eunit:test(meck),它将检测(如果在您的路径上)模块meck_tests并运行meck_tests:test()。当您加入test()时,eunit.hrl函数会被EUnit自动插入到模块中。

至于命名惯例,我通常最终会得到以下内容:

-module(my_tests).

-export([functiona_should_do_this/0]).
-export([functionb_should_do_that/0]).
-export([functionb_should_not_crash/0]).
% etc

如果您想要在测试运行中显示好名称,请使用EUnit的测试生成器功能:

all_my_test_() ->
    [{"Should not break X",  fun first_test/0},
     {"Should perform Y", fun other_test/0}].

任何以test_结尾的函数都告诉EUnit它应该返回一个测试列表(这称为测试生成器)。测试列表可以只包含一个funs列表,一个元组列表,其中第一个元素是测试的字符串描述,或者更复杂的设置:

advanced_test_() ->
    {foreach, fun setup/0, fun teardown/1,
     [{"Assert X", fun test1/0}]}.

这将在每个测试用例之前运行setup/0,在每个测试用例之后运行teardown/1teardown/1的参数是setup/0的返回值。您可以根据需要命名这些功能。

有关如何使用EUnit available here的全面文档。

以下是我的测试模块的外观:https://github.com/eproxus/meck/blob/master/test/meck_tests.erl

答案 1 :(得分:11)

亚当给了你一个方法。另一种方法(更常见的方法,在我有限的经验中)是将单元测试放在每个模块的末尾like this。这样你就可以将模块和它的测试代码组合在同一个文件中。如果测试函数的名称以“_test”结尾,则当您调用eunit时,EUnit会自动识别它们:test(模块)或模块:test()(您不必自己编写模块:test()函数,EUnit为你出口。)

至于多个测试功能:如果你不愿意,你没有这样做。如果您愿意,可以将所有测试用例堆叠在同一个函数中,例如:

whatever_test() ->
    234 = foo(bar),
    345 = foo(baz),
    [...]
    foobar = quux(baz).

就是这样。有些人喜欢将evey测试放在自己的函数中,有些人只在一个函数中叠加它。我通常在一个函数中对类似的测试进行分组,最终得到3-4-5个测试函数。看看哪些适合你。

至于“全球测试模块”,亚当再一次给了你很好的建议。而且,还有另一种选择:rebar。它是一个帮助您测试erlang应用程序(以及更多)的工具。请参阅此处获取教程:http://vimeo.com/8311407 Rebar将自动检测模块中的测试函数并为您运行。