Pex(测试生成)真的有用吗?

发布于 2024-08-30 20:18:24 字数 471 浏览 6 评论 0原文

是的,可以为“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 真的有用吗?

Yes, it is possible to generate tests on boundary values for functions like "Sum" or "Divide". Pex is a good tool here.

But more often we create tests on business behaviour. Let's consider example from classic Beck's tdd book:

[Test]
public void ShouldRoundOnCreation()
{
  Money money = new Money(20.678);
  Assert.AreEqual(20.68,money.Amount);
  Assert.AreEqual(2068,money.Cents);
}

Can this test be generated? No :) 95 % of tests in my projects check business logic, and can not be generated.

Pex (Especially in pair with Moles) can give 100% code coverage, but a high code coverage rate of a test suite does never indicate, that code is well tested - It only gives false confidence that everything is tested. And this is very dangerous.

So, the question is - Is Pex really useful tool?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怀里藏娇 2024-09-06 20:18:24

我认为您错误地使用了 Pex:我们强烈建议用户在参数化单元测试中编写断言。

如果您编写断言,Pex 将尝试系统地使它们无效 - 这就是 Pex 的强大之处:您编写的断言越多,它就越会尝试为您查找错误。

如果您使用 Pex 获得高代码覆盖率测试套件而不编写断言,您只会得到您所要求的:代码覆盖率和有保证的运行时异常。 Pex“仅”尝试覆盖分支(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”类可能是幂等的:如果您将“Amount”的值反馈到 Money 实例中,您将得到 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 成为一个有用的工具?你来当法官吧。

I think you are mistaken in the way Pex should be used: we highly recommend users to write assertions in their parameterized unit tests.

If you write assertions, Pex will try systematically to invalidate them - that's where the power of Pex comes in: the more you write assertions, the more it tries to find bugs for you.

If you use Pex to get a high code coverage test suite without writing assertions, you only get what you asked for: code coverage and guaranteed runtime exceptions. Pex 'only' tries to cover branches (1 assertion = 1 branch), if there are no branches to cover (no assertion), it won't generate interresting test cases.

In general, writing assertions in parameterized unit tests are harder to write because... well they are more general. Let's start with the rounding behavior: there is certainly a bound on which you allow rounding to occur, this should translate naturally into a parameterized unit test:

[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);
}

There are also a number of patterns that can be used to write those. For example, your 'Money' class is probably idempotent: if you feed the value of 'Amount' back in a Money instance, you get Amount back. This translate elegantly into a parameterized unit test:

[PexMethod]
public void RoundIsIdempotent(double value) 
{
     var first = new Money(value).Amount;
     var second = new Money(first).Amount;
     Assert.AreEqual(first, second, 0.0001);
}

Note also, that parameterized unit tests definitely belong in the TDD world. Just write the parameterized unit test first, Pex will find the failing bug, fix the bug, Pex finds the next failing bug, etc...

Does this make Pex a useful tool? You be the judge.

Pex 有一些有用的东西。

  1. 代码覆盖率。让我们先把 Pex 放在一边。一般来说,100% 的代码覆盖率并不一定意味着您具有良好的代码覆盖率。它只是意味着执行了所有路径,但是程序具有数据流,并且测试代码不同的附加输入,即使不是代码覆盖率,也可以为您提供最佳的“测试覆盖率”。在此,我只是重申一下你的观点。 100% 的代码覆盖率不一定好,但可以肯定地说 25% 的代码覆盖率不好,所以这就是代码覆盖率的用处。当代码覆盖率较低时,您肯定知道测试覆盖率较低。

    当您使用 Pex 获得 100% 的代码覆盖率时,它本身并不能真正帮助您获得更好的测试覆盖率,但它的作用是对生产代码的每一段进行一些测试,这可用于调试器。事实上,一次 Pex 会议演示就展示了 Pex 的用途。程序员说:“哎呀,看看 NHibernate 中的这个方法。我想在调试器中单步执行它,看看它做了什么,但是我如何通过正常的“业务入口点”调用该方法?库?如果你对库一无所知,你就不能。所以他运行了 Pex,并且能够使用各种参数来单步执行代码。有趣的是,有用,也许有用,也许没有。

  2. 库?对库一无所知 对于自动创建的测试,Pex 对于参数化测试也很有用。为什么要一遍又一遍地使用不同的参数编写相同的代码,并从数据中提供参数。 除了自动创建的测试之外,Pex 对于参数化测试也很有用,
  3. Pex 也可用作简单的存根框架。这可能是创建模拟对象最简单的方法,使用新的 lambda 表达式,这比 RhinoMocks 等复杂框架更容易理解。使用 Moles,您不仅可以存根接口,还可以存根类中的具体非虚拟方法。

  4. 我也会对“业务逻辑测试”层非常小心。您可以轻松进行行为驱动开发,这不适用于单元测试。在那里,您正在根据规范进行测试。如果这就是您所做的全部,那么您将如何测试自定义数据结构等,这些数据结构没有业务价值,而是在整个应用程序中使用的内部库。

There's a few things useful in Pex.

  1. Code coverage. Let's put Pex aside for a second. In general, 100% code coverage doesn't necessarily mean you have good code coverage. It just means ever path is executed, but program has data-flow, and testing that code different, additional inputs, gives you best "test coverage", if not code coverage. Here's, I'm just reiterating your point. 100% code coverage is not necessarily good, but you can say for sure that 25% code coverage is bad, so that's how code coverage is useful. When you have low code coverage, you know for sure you have low test coverage.

    When you use Pex to get 100% code coverage, it's not really helping you get better test coverage per se, but what it does do is give ever piece of the production code some test, which can be used for debugger. In fact, a Pex presentation as a conference shows the use of Pex for this very purpose. The programmer said, "Gee, look at this method in NHibernate. I'd like to step through it in a debugger to see what it does, but how do I even invoke that method through the normal "business-entry point" into the library? Without knowing anything about the library, you can't. So he ran Pex, and was able to step through the code with all sorts of parameters. Interesting, Yes. Useful, maybe so, maybe no.

  2. In addition to automatically created tests, Pex is also useful for parameterizing your tests. It's much better to create unit tests that are data driven. Why write the same code over and over, with different parameters. Write it once, and feed the parameters from a data source.

  3. Pex is also useful as a simple stubbing framework. It's probably the easiest way to create mock objects, using the new lambda expression, which is much easier to understand than complex frameworks like RhinoMocks, etc. With Moles, you can also stub not just interface, but concrete non-virtual methods in classes.

  4. I would also be careful with the "testing at the business logic" layer, too much. You could easy get to doing Behavioral Driven Development, which is not for unit testing. There, you are testing against a spec. If that's all you did, how would you test, say, custom data structures, etc., that have no business value, but are internal libraries used throughout the application.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文