没有断言的单元测试

时间:2008-09-26 02:26:25

标签: unit-testing assert

偶尔我会遇到一个没有断言的单元测试。我今天早上遇到的特定示例是测试在满足条件时写入日志文件。假设是如果没有抛出错误,则测试通过。

我个人对此没有任何问题,但是编写一个没有任何关联断言的单元测试似乎有点“代码味道”。

只是想知道人们对此的看法是什么?

14 个答案:

答案 0 :(得分:19)

这只是一个非常小的测试,应该记录在案。它仅验证它在运行时不会爆炸。关于这样的测试最糟糕的部分是它们呈现出一种虚假的安全感。你的代码覆盖率会上升,但这是虚幻的。非常难闻的气味。

答案 1 :(得分:17)

这是正式的做法:

// Act
Exception ex = Record.Exception(() => someCode());

// Assert
Assert.Null(ex);

答案 2 :(得分:12)

如果没有断言,则不是测试。

退出懒惰 - 可能需要一点时间来弄清楚如何在那里得到断言,但值得知道它做了你期望它做的事。

答案 3 :(得分:6)

这样的测试闻起来。它应检查文件是否已写入,至少修改后的时间可能已更新。

我已经看过很多以这种方式编写的测试,最终没有测试任何东西,即代码不起作用,但它也没有爆炸。

如果您有一些明确的要求,即测试中的代码不会抛出异常并且您想明确地调出这个事实(测试为需求文档),那么我会做这样的事情:

try
{
  unitUnderTest.DoWork()
}
catch
{
  Assert.Fail("code should never throw exceptions but failed with ...")
}

......但这对我来说仍然有点味道,可能是因为它试图证明是消极的。

答案 4 :(得分:6)

这些被称为冒烟测试并且很常见。他们是基本的健全检查。但它们不应该是你拥有的唯一一种测试。你还需要在另一个测试中进行某种验证。

答案 5 :(得分:2)

在某种意义上,您正在进行隐式断言 - 代码不会抛出异常。当然,实际获取文件并找到合适的行会更有价值,但我认为有些东西比什么都好。

答案 6 :(得分:2)

总的来说,我在集成测试中看到了这种情况,只是事情已经成功完成了。在这种情况下,我很酷。

我想如果我在单元测试中一​​遍又一遍地看到它,我会很好奇这些测试的真实性。

编辑:在OP给出的示例中,有一些可测试的结果(日志文件结果),所以假设如果没有抛出它工作的错误是懒惰的。

答案 7 :(得分:2)

这可能是一个很好的实用解决方案,特别是如果替代方案根本没有测试。

问题是如果调用的所有函数都是no-ops,测试就会通过。但有时候验证副作用是否符合预期是不可行的。在理想的世界中,有足够的时间为每次测试编写支票......但我不住在那里。

我使用此模式的另一个地方是在单元测试中嵌入一些性能测试,因为这是让它们在每次构建时运行的简单方法。测试没有断言任何东西,但是测量测试花了多长时间并记录下来。

答案 8 :(得分:1)

之前我见过这样的事情,我认为这只是为了支持代码覆盖率。它可能不是真正测试代码行为。无论如何,我同意将其(意图)记录在测试中以保持清晰。

答案 9 :(得分:1)

测试的名称应该记录下来。

void TestLogDoesNotThrowException(void) {
    log("blah blah");
}

测试如何验证是否在没有断言的情况下写入日志?

答案 10 :(得分:0)

我必须承认,我从未编写过单元测试,证明我正确记录。但我确实考虑过这个问题并且遇到了discussion如何使用JUnit和Log4J来完成它。它不太漂亮,但它看起来会起作用。

答案 11 :(得分:0)

测试应该始终断言,否则你会证明什么,以及如何能够始终如一地复制代码有效的证据?

答案 12 :(得分:0)

我们一直这样做。我们使用JMock模拟我们的依赖项,所以我想在某种意义上JMock框架正在为我们做断言......但它就是这样的。我们有一个想要测试的控制器:

Class Controller {
  private Validator validator;

  public void control(){
    validator.validate;
  }

  public setValidator(Validator validator){ this.validator = validator; }
}

现在,当我们测试Controller时,我们不想测试Validator,因为它有自己的测试。所以我们对JMock进行了测试,以确保我们调用validate:

public void testControlShouldCallValidate(){
  mockValidator.expects(once()).method("validate");
  controller.control;
}

就是这样,没有“断言”可以看到,但是当你调用控件并且没有调用“validate”方法时,JMock框架会抛出一个异常(类似于“未调用的预期方法”等)。

我们到处都有。这有点落后,因为你基本上设置你的断言,然后调用测试方法。

答案 13 :(得分:0)

我有时会使用我选择的单元测试框架(NUnit)来构建充当代码特定部分入口点的方法。这些方法对于分析代码子集的性能,内存消耗和资源消耗非常有用。

这些方法绝对不是单元测试(即使它们标有 [Test] 属性),并且总是被标记为在被检入源代码管理时被忽略并明确记录。

我偶尔也会将这些方法用作Visual Studio调试器的入口点。我使用Resharper直接进入测试,然后进入我想要调试的代码。这些方法或者没有使它成为源代码控制,或者它们获得了它们自己的断言。

我的“真正的”单元测试是在正常的TDD周期中构建的,它们总是断言,但并不总是直接 - 有时断言是模拟框架的一部分,有时候我能够将类似的断言重构为单个方法。这些重构方法的名称总是以前缀“Assert”开头,这对我来说很明显。