在编写单元测试时断言 "nothing happened"
Assert that "nothing happened" when writing unit test
在写单元测试的时候,有什么简单的方法可以保证不出意外吗?
由于可能的副作用列表是无限的,添加大量断言以确保在每一步都没有改变似乎是徒劳的,它混淆了测试的目的。
我可能错过了一些框架功能或良好实践。
我正在使用 C#7、.net 4.6、MSTest V1。
编辑:
更简单的示例是测试视图模型的 setter,应该发生两件事:值应该更改并且应该引发 PropertyChanged 事件。
这两件事很容易检查,但现在我需要确保其他属性值没有改变,没有引发其他事件,没有触及系统剪贴板...
您错过了单元测试的要点。他们是"proofs"。你无法从逻辑上证明一个否定的断言,所以即使尝试也没有意义。
每个单元测试中的断言应证明所需的行为已完成。就这些了。
如果我们将问题简化为荒谬,每个单元测试都需要我们断言被测函数没有启动热核war。
单元测试不是您需要执行的唯一一种测试。有功能测试、集成测试、可用性测试等,各有侧重。对于单元测试,重点是证明单个功能的预期行为。因此,如果该函数应该完成两件事,只需断言这两件事都发生了,然后继续。
对您的编辑的一些补充:
在 Test Driven Development 中,您只编写代码,这将通过测试,仅此而已。此外,您想选择最简单的解决方案来实现此目标。
也就是说,您很可能会从失败的单元测试开始。在你的情况下,你不会在开始时得到一个失败的单元测试。
如果你将它推到极限,当你想检查每一个结果时,你必须检查 format C:\
没有在你的应用程序中调用。您可能想看看设计原则,例如 KISS-原则(保持简单,愚蠢)。
如果 "check that nothing else happened" 的范围是确保模型的状态没有改变,那么问题就是这种情况。
编写一个辅助函数,在你的事件之前和之后获取模型并比较它们。让它 return 更改的属性,然后您可以断言只有那些您打算更新的属性在 return 列表中。这种助手是可移植的、可维护的和可重用的
检查模型状态是单元测试的有效应用。
确保没有 'bad' 或意外情况发生的方法之一是确保使用依赖注入和模拟的良好实践:
[Test]
public void TestSomething()
{
// Arrange
var barMock = RhinoMocks.MockRepository.GenerateStrictMock<IBar>();
var foo = new Foo(barMock);
// Act
foo.DoSomething();
// Assert
...
}
在上面的示例中,如果 Foo
不小心触及 Bar
,将导致异常(严格模拟)并且测试失败。这种方法可能不适用于所有测试用例,但可以作为对其他潜在实践的一个很好的补充。
这仅适用于引用透明的语言,例如 Safe Haskell。
在写单元测试的时候,有什么简单的方法可以保证不出意外吗?
由于可能的副作用列表是无限的,添加大量断言以确保在每一步都没有改变似乎是徒劳的,它混淆了测试的目的。
我可能错过了一些框架功能或良好实践。
我正在使用 C#7、.net 4.6、MSTest V1。
编辑: 更简单的示例是测试视图模型的 setter,应该发生两件事:值应该更改并且应该引发 PropertyChanged 事件。 这两件事很容易检查,但现在我需要确保其他属性值没有改变,没有引发其他事件,没有触及系统剪贴板...
您错过了单元测试的要点。他们是"proofs"。你无法从逻辑上证明一个否定的断言,所以即使尝试也没有意义。
每个单元测试中的断言应证明所需的行为已完成。就这些了。
如果我们将问题简化为荒谬,每个单元测试都需要我们断言被测函数没有启动热核war。
单元测试不是您需要执行的唯一一种测试。有功能测试、集成测试、可用性测试等,各有侧重。对于单元测试,重点是证明单个功能的预期行为。因此,如果该函数应该完成两件事,只需断言这两件事都发生了,然后继续。
对您的编辑的一些补充:
在 Test Driven Development 中,您只编写代码,这将通过测试,仅此而已。此外,您想选择最简单的解决方案来实现此目标。
也就是说,您很可能会从失败的单元测试开始。在你的情况下,你不会在开始时得到一个失败的单元测试。
如果你将它推到极限,当你想检查每一个结果时,你必须检查 format C:\
没有在你的应用程序中调用。您可能想看看设计原则,例如 KISS-原则(保持简单,愚蠢)。
如果 "check that nothing else happened" 的范围是确保模型的状态没有改变,那么问题就是这种情况。
编写一个辅助函数,在你的事件之前和之后获取模型并比较它们。让它 return 更改的属性,然后您可以断言只有那些您打算更新的属性在 return 列表中。这种助手是可移植的、可维护的和可重用的
检查模型状态是单元测试的有效应用。
确保没有 'bad' 或意外情况发生的方法之一是确保使用依赖注入和模拟的良好实践:
[Test]
public void TestSomething()
{
// Arrange
var barMock = RhinoMocks.MockRepository.GenerateStrictMock<IBar>();
var foo = new Foo(barMock);
// Act
foo.DoSomething();
// Assert
...
}
在上面的示例中,如果 Foo
不小心触及 Bar
,将导致异常(严格模拟)并且测试失败。这种方法可能不适用于所有测试用例,但可以作为对其他潜在实践的一个很好的补充。
这仅适用于引用透明的语言,例如 Safe Haskell。