Mik*_*ike 29 perl unit-testing
我是Perl的新手,我想知道是否有一个首选的单元测试框架?
谷歌向我展示了一些不错的结果,但由于我是新手,我不知道社区内是否有明确的偏好.
Rob*_*t P 37
Perl有一套很棒的测试工具随附!Perl核心有几万个自动检查,并且大多数情况下它们都使用这些标准的Perl框架.他们都使用TAP捆绑在一起 - 测试任何协议.
在Perl中创建TAP测试的标准方法是使用Test :: More系列包,包括Test :: Simple入门.这是一个简单的例子:
use 5.012;
use warnings;
use Test::More tests => 3;
my $foo = 5;
my $bar = 6;
ok $foo == 5, 'Foo was assigned 5.';
ok $bar == 6, 'Bar was assigned 6.';
ok $foo + $bar == 11, 'Addition works correctly.';
Run Code Online (Sandbox Code Playgroud)
输出将是:
ok 1 - Foo was assigned 5.
ok 2 - Bar was assigned 6.
ok 3 - Addition works correctly.
Run Code Online (Sandbox Code Playgroud)
基本上,要开始,您需要做的就是传递一个布尔值和一个解释应该发生什么的字符串!
一旦你超越了这个步骤,Test :: More就会有大量的其他函数让测试更容易(字符串,正则表达式比较,深层结构比较),还有Test :: Harness后端可以测试大型组将各个测试脚本放在一起.
最重要的是,正如Schwern指出的那样,几乎所有的现代Test::模块都在一起工作.这意味着你可以使用Test::Class(正如Markus所指出的)rjh的答案中列出的所有伟大的模块.事实上,因为Test :: Builder - Test::More和其他人建立的工具(目前由Schwern维护......感谢Schwern!) - 如果需要,你可以从头开始构建你的OWN测试子程序与所有其他测试框架一起工作.仅此一点就使Perl的TAP系统成为我认为最好的系统之一:一切都在一起工作,每个人都使用相同的工具,你可以通过很少的额外工作添加到框架中以满足您的需求.
rjh*_*rjh 13
Perl最受欢迎的测试'框架'是一种称为TAP(Test Anything Protocol)的测试结果格式,它是一组字符串,如下所示:
ok 1 - Imported correctly
ok 2 - foo() takes two arguments
not ok 3 - foo() throws an error if passed no arguments
Run Code Online (Sandbox Code Playgroud)
任何可以生成这些字符串的脚本都算作Perl测试.您可以使用Test :: More为各种条件生成TAP - 检查变量是否等于值,检查模块是否正确导入,或者两个结构(数组/散列)是否相同.但是在真正的Perl精神中,有不止一种方法可以做到,还有其他方法(例如Test :: Class,看起来有点像JUnit!)
测试脚本的一个简单的例子(它们通常结束.t,例如foo.t)
use strict;
use warnings;
use Test::More tests => 3; # Tell Test::More you intend to do 3 tests
my $foo = 3;
ok(defined $foo, 'foo is defined');
is($foo, 3, 'foo is 3');
$foo++;
is($foo, 4, 'incremented foo');
Run Code Online (Sandbox Code Playgroud)
您可以使用Test :: Harness(通常prove从shell 调用)按顺序运行一系列测试,并获得哪些测试通过或失败的摘要.
测试::更多也可以做一些更复杂的事情,比如标记测试为TODO(不要指望它们通过,但只是以防万一)或SKIP(这些测试被破坏/可选,不运行它们).您可以声明您希望运行的测试数量,因此如果您的测试脚本中途中断,则可以检测到这一点.
一旦开始进行更复杂的测试,您可能会发现其他一些CPAN模块很有用 - 这里有一些例子,但还有很多(很多):
Test :: Exception - 测试您的代码是否抛出错误/不会抛出任何错误
Test :: Warn - 测试您的代码执行/不生成警告
Test :: Deep - 深度比较对象.它们不必相同 - 您可以忽略数组排序,使用正则表达式,忽略对象类等
.Test :: Pod - 确保您的脚本具有POD(文档),并且它是有效的
Test :: Pod ::覆盖范围 - 确保您的POD记录模块中的所有方法/函数
Test :: DBUnit - 测试数据库交互
Test :: MockObject - 制作假装对象来控制测试环境
如果您练习TDD,您会注意到您的单元测试集正在改变很多.Test :: Class遵循xUnit模式(http://en.wikipedia.org/wiki/XUnit).
对我来说,xUnit的主要好处是在方法中封装每个测试.框架通过测试方法的名称命名每个断言,并添加在每次测试之前和之后运行setup-and teardown方法的可能性.
我也尝试了"perl-ish"方式进行单元测试(仅使用Test :: More),但我发现它有点老式和繁琐.
一些反建议可能是这样的:
反推荐:
不要使用Test::UnitPerl 测试包系列,例如Test::Unit::Assert和Test::Unit::TestCases。
原因:Test::Unit似乎被遗弃了。
Test::Unit、Test::Unit::TestCases、Test::Unit::Assert 工作得很好(当我在 2015-2016 年使用它们时)。Test::Unit 据说没有与 Perl 的 Test Anything Protocol (TAP) 集成,尽管我发现这很容易修复。
但是 Test::Unit 令人沮丧,因为许多其他 Perl 测试包大多使用 Test::Builder 构建,例如 Test::More、Test::Most、Test::Exception、Test::Differences、Test::Deep 、Test::Warn 等与 Test::Unit 的面向对象测试方法不能很好地交互。
一旦您将 Test::Unit 调整为与 Test::More 和 TAP 一起使用,您就可以混合 Test::Unit 测试和 Test::Builder 测试;但这些其他包的良好特性无法用于 OO 扩展。无论如何,这就是使用 xUnit 样式测试的主要原因。
据说 CPANTest::Class允许“以 xUnit/JUnit 样式轻松创建测试类”——但我不确定我是否可以推荐这样做。对我来说,它当然不像 xUnit - 不是 OO,而是像 那样的特殊名称,is(VAL1,VAL2,TESTNAME)而不是 xUnit 样式名称$test_object->assert_equals(VAL1,VAL2,TEST_ERR_MSG)。Test::Class 确实具有自动检测注释为 :Test 的所有测试的令人愉快的功能,与 xUnit 和 TEST::Unit::TestCase 使用内省运行所有名为 test_* 的函数的方法相当。
然而,底层包Test::Builder是面向对象的,因此更具 xUnit 风格。不要被这个名字吓到——它不是一个工厂,它主要是一个带有测试断言方法的套件。尽管大多数人继承自它,但如果您愿意,您可以直接调用它,例如$test_object->is(VAL1,VAL2,TESTNAME),并且通常您可以使用 Test::Builder 调用来解决程序包的限制,例如构建在 Test:: 之上的 Test::More 。 Builder - 例如修复报告错误的调用堆栈级别。
Test::Builder 通常使用单例样式,但可以创建多个对象。我不确定这些行为是否符合 xUnit 系列测试的预期。
到目前为止,没有简单的方法可以解决限制,例如 Perl TAP 测试使用 TEST_NAMES,每个断言,没有层次结构,并且不区分 TEST_NAMES 和 TEST_ERROR_MESSAGES。(错误报告级别有助于弥补这一缺陷。)
可以创建一个适配器,使 Test::Builder 和 TAP 样式测试更加面向对象,以便您可以基于 TAP 以外的其他内容进行变基(它记录比 TAP 更有用的信息 - 据说类似于 ANT 的 XML 协议)。我认为调整名称和/或缺失的概念将涉及进入 Test::Builder 或内省。