为什么这个特殊的测试可能有用

本文关键字:测试 有用 为什么 | 更新日期: 2023-09-27 18:16:57

我最近加入了一家使用TDD的公司,但对我来说仍然不清楚,例如,我们有一个测试:

[TestMethod]
public void ShouldReturnGameIsRunning()
{
    var game = new Mock<IGame>();
    game.Setup(g => g.IsRunning).Returns(true);
    Assert.IsTrue(game.Object.IsRunning);
}

目的是什么?据我所知,这是在测试什么!我这么说是因为它模拟了一个接口,它说,IsRunning返回true,它永远不会返回一个不同的值。

我可能想错了,因为每个人都说这是一个很好的实践等等…还是这个测试错了?

为什么这个特殊的测试可能有用

这个测试正在测试一个接口,并验证该接口公开了一个名为IsRunning的布尔getter。

这个测试可能是在interface存在之前编写的,也可能是在IGame的任何具体类存在之前编写的。我可以想象,如果项目具有任何成熟度,就会有其他测试来测试实际实现并验证该级别的行为,并且可能在更传统的孤立主义上下文中使用mock,而不是存根理论形状。

这类测试的价值在于它迫使人们思考如何使用形状或对象。类似于"我还不知道游戏到底要做什么,但我知道我想要检查它是否正在运行……"所以这种风格的测试更多的是驱动设计决策,以及验证行为。

不是这个星球上最有价值的测试,但在我看来,它达到了它的目的。

编辑:当我昨晚在火车上打字的时候,我想在回答中直接针对Andrew Whitaker的评论。

有人可能会说,接口中的签名本身就足以实现期望的契约。然而,这实际上取决于你如何对待你的接口,以及最终你如何验证你要测试的系统。

显式地将此功能声明为测试可能具有实际价值。您正在明确地验证这是IGame所需的功能。

让我们举一个用例,假设作为一个设计者,你知道你想为IsRunning公开一个公共getter,所以你把它添加到接口中。但是,假设另一个开发人员获得了这个属性并看到了这个属性,但在代码的其他地方没有看到它的任何用法,那么人们可能会认为它有资格删除(或代码腐烂删除,这通常是一件好事)而不会造成损害。然而,这个测试的存在性明确地声明了这个属性应该存在。

如果没有这个测试,开发人员可以修改接口,删除实现,项目仍然可以正常编译和运行。直到很久以后,才会有人注意到界面已经改变了。

使用这个测试,即使看起来好像没有人在使用它,您的测试套件也会失败。测试的自记录性质告诉您,如果IGame确实应该公开IsRunning getter,那么ShouldReturnGameIsRunning()至少应该生成一个对话。

测试无效。Moq是一个用于"模拟"被测试方法使用的对象的框架。如果您正在测试IsRunning,您可以使用Mock为IsRunning所依赖的那些方法提供特定的实现,例如导致执行某些执行路径。

人们可以整天告诉你先测试更好;你不会意识到它实际上是,直到你自己开始这样做,并意识到你的代码的bug更少,你首先写测试,这将节省你和你的同事的时间,并可能使你的代码质量更高。

这可能是测试已经编写(之前)的代码,这是良好的实践。

同样,这可能是一个由工具创建的无意义的测试。

另一种可能性是代码是由当时不了解如何使用特定mock框架的人编写的,并且编写了一个或多个简单的测试来学习。Kent Beck在他最初的TDD书中谈到了这种"学习测试"。

这个测试在过去是有意义的。它可能是在测试一个具体类。它可能是在测试一个抽象类——因为有时模拟想要测试的抽象类是有意义的。我可以看到(像我一样不太了解)TDD做事方式的追随者是如何留下这样的小混乱的。清理死代码和死测试代码,并不符合红、绿、重构的自然工作流程(因为它不会破坏任何测试!)然而,历史并不能成为一个只会让读者感到困惑的测试的理由。所以,做个好男孩,把它取下来。

在我看来这只是垃圾,它只是证明moq工作如预期