Unit testing 有没有办法对副作用进行单元测试?
任何代码都可能产生副作用。大多数情况下,副作用可能是糟糕设计和/或重构需求的标志,但当我发现很难针对单元测试进行测试时。考虑下面的例子:Unit testing 有没有办法对副作用进行单元测试?,unit-testing,side-effects,Unit Testing,Side Effects,任何代码都可能产生副作用。大多数情况下,副作用可能是糟糕设计和/或重构需求的标志,但当我发现很难针对单元测试进行测试时。考虑下面的例子: [Test] public void TrimAll_Removes_All_Spaces() { // Arrange var testSubject = "A string with lots of space"; var expectedResult = "Astringwithlotsofspace"
[Test]
public void TrimAll_Removes_All_Spaces()
{
// Arrange
var testSubject = "A string with lots of space";
var expectedResult = "Astringwithlotsofspace";
// Act
var result = testSubject.TrimAll();
// Assert
Assert.AreEqual(expectedResult, result);
}
这将测试以下扩展:
public static string TrimAll(this string str)
{
PokeAround();
return str.Replace(" ", "");
}
测试将通过,但没有预防副作用。调用PokeAround
的效果将完全不被注意
假设你不知道什么是PokeAround
,它可能是任何东西你如何编写一个测试来防范它?有可能吗
澄清:
关于PokeAround
有一些评论认为完全未知是一个非常不可能的场景,因为我们在编写测试时有了源代码。不过,我问这个问题的原因是想找到一种方法来防止后来增加的副作用。也就是说,当我编写测试时,我可能会让exension方法如下所示:
public static string TrimAll(this string str)
{
return str.Replace(" ", "");
}
考试通过了,一切都很好。然后,一个月后,当我在度假时,一位同事打电话给我。我希望我已经写过的测试失败,因为他失败了。这就是所谓的感知。也就是说,感知调用被测试方法的效果
既然你不知道PokeAround是什么-它可能是任何东西
因为我们谈论的是单元测试,这几乎不应该是真的-单元测试是白盒测试,代码应该在那里供您检查。除非它位于某个封闭源代码的第三方库中,否则在这种情况下,您不需要对它进行测试,也不能根据定义对它进行单元测试(可能您需要功能/验收测试,但这完全是另一回事……)
更新:那么您想确保将来对单元测试方法的更改不会产生任何意外的副作用吗?我想你
你不应该这样做,因为这取决于你的同事在未来做出的改变,来负责他/她的改变的单元测试。如果您不相信会发生这种情况,那么您遇到的是人员或流程问题,而不是单元测试问题。您可以从另一个角度来看,通过为此代码编写单元测试,您将迫使自己承认代码中的问题(副作用)。然后,您可以以可测试的方式重新编写/重构代码,可以将
PokeAround
移动到它自己的函数中,或者如果它需要更多的输入/状态才能进行测试,就将它从您尝试测试的代码中重新定位。我不确定您是否可以。毕竟,它是一种预期效果还是一种副作用取决于设计者的意图
我建议您断言“副作用”代码是不变的
另外,像这样的工具可能会有所帮助,但我不认为它会对您的示例产生影响。取决于您所说的副作用-我的意思是,可能PokeAround()做了一些需要做的重要事情。副作用如何分类 不管怎么说,我所知道的并没有特别的技术/技巧可以防止单单元测试中的副作用,但只要您对所有代码都有测试覆盖率,任何不必要的副作用都有希望通过至少一个测试得到 BDD/集成测试工具也有助于解决这一问题,因为它们(通常)测试更大范围的功能,而不仅仅是单个类/方法
您可能需要了解的一件事是(DBC)。这允许您指定前置和后置条件以及不变量,因此,如果使用无效参数调用方法、返回无效值或对象进入无效状态,将抛出某种错误。不可能。在任何测试阶段,副作用测试都很困难。在不同的项目(产品开发、工具开发、业务应用程序开发、游戏开发等)中是不同的 如果没有完整的回归测试,就无法发现副作用 在一个典型的项目(我经历过)中,“此更改是否有任何副作用”的问题通常会在项目快结束时(接近上线)或当有人想在已经生产的系统中添加热修复程序时被问到。我发现在没有回归测试的情况下,唯一(仍然有风险的)质量控制措施是代码审查 希望能有帮助 考虑到你不知道什么是PokeAround,它可能是任何东西你如何编写一个测试来防范它?有可能吗 这个问题似是而非。这种情况在现实世界中不太可能发生
[Test]
public void TrimAll_Removes_All_Spaces()
{
// Arrange
var testSubject = "A string with lots of space";
var testSubjectCopy = "A string with lots of space";
var expectedResult = "Astringwithlotsofspace";
// Act
var result = testSubject.TrimAll();
// Assert
Assert.AreEqual(expectedResult, result);
// Check for side effects
Assert.AreEqual(testSubjectCopy, testSubject);
}