Pex(测试生成)真的有用吗?
Posted
技术标签:
【中文标题】Pex(测试生成)真的有用吗?【英文标题】:Is Pex (Test generation) really useful tool? 【发布时间】:2011-02-11 21:03:40 【问题描述】:是的,可以为“Sum”或“Divide”等函数生成边界值测试。 Pex 是一个很好的工具。
但更多时候,我们会针对业务行为进行测试。让我们考虑一下经典 Beck 的 tdd 书中的例子:
[Test]
public void ShouldRoundOnCreation()
Money money = new Money(20.678);
Assert.AreEqual(20.68,money.Amount);
Assert.AreEqual(2068,money.Cents);
可以生成这个测试吗?否 :) 我的项目中 95% 的测试检查业务逻辑,并且无法生成。
Pex(尤其是与 Moles 搭配使用)可以提供 100% 的代码覆盖率,但测试套件的高代码覆盖率并不表示代码经过良好测试 - 它只会让人错误地相信所有内容都经过测试。这是非常危险的。
所以,问题是 - Pex 真的有用吗?
【问题讨论】:
【参考方案1】:Pex 中有一些有用的东西。
代码覆盖率。让我们暂时搁置 Pex。一般来说,100% 的代码覆盖率并不一定意味着你有很好的代码覆盖率。这只是意味着执行了任何路径,但是程序具有数据流,并且测试该代码不同的附加输入,如果不是代码覆盖率,则可以为您提供最佳的“测试覆盖率”。在这里,我只是重申你的观点。 100% 的代码覆盖率不一定是好的,但是你可以肯定地说 25% 的代码覆盖率是不好的,所以这就是代码覆盖率的用处。当您的代码覆盖率较低时,您肯定知道您的测试覆盖率较低。
当您使用 Pex 获得 100% 的代码覆盖率时,它本身并不能真正帮助您获得更好的测试覆盖率,但它所做所做的是对生产代码的任何部分进行一些测试,这可用于调试器。事实上,作为会议的 Pex 演示文稿展示了 Pex 用于此目的的用途。程序员说:“哎呀,看看 NHibernate 中的这个方法。我想在调试器中单步调试它,看看它做了什么,但我什至如何通过正常的“业务入口点”调用该方法进入库?在不了解库的情况下,你不能。所以他运行了 Pex,并且能够使用各种参数单步执行代码。有趣,是的。有用,也许有用,也许没有。
除了自动创建的测试外,Pex 还可用于参数化测试。创建数据驱动的单元测试要好得多。为什么一遍又一遍地编写相同的代码,使用不同的参数。编写一次,然后从数据源提供参数。
Pex 也可用作简单的存根框架。这可能是创建模拟对象最简单的方法,使用新的 lambda 表达式,它比 RhinoMocks 等复杂的框架更容易理解。使用 Moles,您不仅可以存根接口,还可以存根类中的具体非虚拟方法。
我也会小心“业务逻辑测试”层,太多了。你可以很容易地进行行为驱动开发,这不是用于单元测试的。在那里,您正在根据规范进行测试。如果这就是您所做的一切,您将如何测试没有商业价值但在整个应用程序中使用的内部库,例如自定义数据结构等。
【讨论】:
1) Yas 100% 的覆盖率并不一定意味着好的,这就是为什么它很危险。 2)您可以使用经典测试在调试器下运行代码。但是,如果您有适当的测试,则需要调试器的情况非常罕见。 3) Nunit 也支持参数化测试,唯一的区别——不生成参数。 4) Moles 可以与 Pex 分开使用。 Moles 在 Rhino 或 Moq 之前的唯一优势是它可以为静态调用和构造函数创建存根(从设计角度来看,这并不好)。 5) BDD - 只是 TDD 的子集,以稍微不同的方式完成。 小心说这很危险。仅仅因为它可以被滥用并不意味着它也不能有用。 BDD 不是 TDD 的子集——BDD 处于更高级别,它捕获用户故事、行为,而单元测试捕获代码的结构和设计。 我并没有说 Pex 无用和危险,因为它可以提供 100% 的覆盖率。我刚刚说过,100% 的覆盖率会产生错误的信心。关于 BDD - 您不认为可以在常规测试(单元、集成和功能)中捕获用户故事吗? (code-magazine.com/article.aspx?quickid=0805061&page=1最后一段) 这个答案是基于一个又一个假前提。不想争论,只是指出来。 第 3 点与 PEX 无关,应从答案中删除。在 VS 2012 中,痣已被假货取代【参考方案2】:我认为您在使用 Pex 的方式上是错误的:我们强烈建议用户在其参数化单元测试中编写断言。
如果您编写断言,Pex 将系统地尝试使它们无效 - 这就是 Pex 的强大之处:您编写的断言越多,它就越会尝试为您查找错误。
如果您在不编写断言的情况下使用 Pex 获得高代码覆盖率测试套件,那么您只会得到您所要求的:代码覆盖率和保证的运行时异常。 Pex 'only' 尝试覆盖分支(1 个断言 = 1 个分支),如果没有要覆盖的分支(无断言),它将不会生成有趣的测试用例。
一般来说,在参数化单元测试中编写断言更难编写,因为……它们更通用。让我们从舍入行为开始:肯定存在允许舍入发生的界限,这应该自然地转化为参数化单元测试:
[PexMethod]
public void RoundInBounds(double value)
var money = new Money(value);
// distance between value and amount should be at most 0.01/2
Assert.AreEqual(value, money.Amount, 0.005);
还有许多模式可用于编写这些模式。例如,您的“Money”类可能是幂等的:如果您在 Money 实例中返回“Amount”的值,您将获得 Amount。这可以优雅地转化为参数化单元测试:
[PexMethod]
public void RoundIsIdempotent(double value)
var first = new Money(value).Amount;
var second = new Money(first).Amount;
Assert.AreEqual(first, second, 0.0001);
还要注意,参数化单元测试绝对属于 TDD 世界。只需先编写参数化的单元测试,Pex 会找到失败的错误,修复错误,Pex 找到下一个失败的错误,等等...
这会使 Pex 成为有用的工具吗?你是法官。
【讨论】:
简而言之:1) Pex 无法自行生成足够的测试。 2) 可用于为参数化测试生成参数。第二个很有用,同意。但是回归呢?如果我发现代码 sn-p 失败,参数 = 123,43,可能我想在 nunit 参数化测试中保存这种情况。您是否尝试过混合使用 pex 和 nunit 参数化测试? 出于好奇,为什么在使用 Visual Studio 时使用 NUnit? 相比 MSTest,我更喜欢 NUnit,因为它更完整。但是我真的没有反对 MSTest 的任何东西。 欢迎您将传统单元测试和参数化单元测试混合使用:参数化单元测试只是带参数的方法。如果您需要添加回归场景,只需添加它 - 不要拘泥于一种方法,拥抱所有方法。 Pex 可以为 MSTest、NUnit、xUnit.net 或 MbUnit 开箱即用地生成单元测试。事实上,它是可扩展的,因此您也可以提出自己的单元测试框架并将其集成。以上是关于Pex(测试生成)真的有用吗?的主要内容,如果未能解决你的问题,请参考以下文章