我目前正在学习Erlang,并且想知道单元测试的一些好的做法或惯例是什么?我目前正在使用eunit。
构思这个问题:
我目前正在为每个函数编写一个单元测试模块,这样我的测试名称非常简单,并采用了should_do_desired_behaviour_test()的形式。
我开始为我正在编写的每个模块使用一个模块,但感觉不对,因为命名测试变得越来越笨重,并且测试模块感觉杂乱无章。
我所采用的方法预见的问题是,我最终会得到许多需要执行的模块。然后,我将需要某种全局模块来运行每个测试模块中的所有测试。
所以我想我不太确定采取什么方法,或者我是否正确地走上正轨。你通常如何管理单元测试?
干杯。
答案 0 :(得分:24)
迄今为止最常见的方法是每个应用程序模块一个测试模块。如果您正确命名模块,EUnit将为您找到并运行所有测试,无需创建运行测试的全局模块。例如,给定:
如果您运行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/1
。 teardown/1
的参数是setup/0
的返回值。您可以根据需要命名这些功能。
有关如何使用EUnit available here的全面文档。
以下是我的测试模块的外观:https://github.com/eproxus/meck/blob/master/test/meck_tests.erl
答案 1 :(得分:11)
至于多个测试功能:如果你不愿意,你没有这样做。如果您愿意,可以将所有测试用例堆叠在同一个函数中,例如:
whatever_test() ->
234 = foo(bar),
345 = foo(baz),
[...]
foobar = quux(baz).
就是这样。有些人喜欢将evey测试放在自己的函数中,有些人只在一个函数中叠加它。我通常在一个函数中对类似的测试进行分组,最终得到3-4-5个测试函数。看看哪些适合你。
至于“全球测试模块”,亚当再一次给了你很好的建议。而且,还有另一种选择:rebar。它是一个帮助您测试erlang应用程序(以及更多)的工具。请参阅此处获取教程:http://vimeo.com/8311407 Rebar将自动检测模块中的测试函数并为您运行。