当逻辑基本相同时,复制和粘贴unit testing是否可以?

我目前有10个测试,只要路径中有一块或墙壁,我的俄罗斯方块片就不会向左移动。 现在,我将不得不为正确的运动测试相同的行为。

如果我只是复制我已经拥有的左侧运动的10个测试并且仅进行所需的更改并且对代​​码本身执行相同的操作,那是不是太糟糕了? 或者,如果逻辑基本相同,我应该从头开始再进行每次测试吗?

尝试采用您未提及的第3种方法,即重构代码,以便在所有10个测试之间共享测试的一个实现。

问题是,复制代码几乎总是错误的。 在此示例中,您可以将检查代码重构为一个名为IsTetrisPieceUnableToMoveLeftBecauseOfAPieceOrAWall 。 在为unit testing编写一些“共享”function时,我总是寻找非常具有描述性的方法名称,因为它使得它非常清楚正在完成/测试的内容。

我对这个问题有一点争议。 虽然生产代码中必须尽可能避免代码重复,但这对于测试代码来说并不是那么糟糕。 生产和测试代码的性质和意图不同

  • 生产代码可以提供一些复杂性以便可理解/可维护。 您希望代码处于正确的抽象级别,并使设计保持一致。 这是好的,因为你有测试,你可以确保它的工作。 如果您在逻辑级别实际拥有100%的代码覆盖率,则生产代码中的代码重复不会成为问题。 这实际上很难实现,因此规则是:避免重复并最大化代码覆盖率。

  • 另一方面, 测试代码必须尽可能简单。 您必须确保测试代码实际测试它应该是什么。 如果测试很复杂,你可能会在测试或错误测试中遇到错误 – 而且你没有测试测试,因此规则是:保持简单。 如果测试代码是重复的,那么当它发生变化时,这不是一个大问题。 如果更改仅在一次测试中应用,则另一次测试将失败,直到您修复它为止。

我想说的主要观点是生产和测试代码具有不同的性质。 然后它总是一个常识问题,我不是说你不应该考虑测试代码,等等。如果你可以在测试代码中考虑一些因素,你确定它没问题,那就去做吧。 但是对于测试代码,我倾向于简单而不是优雅,而对于生产代码,我更喜欢优雅而不是简单。 最佳的当然是拥有一个简单,优雅的解决方案:)

PS:如果你真的不同意,请发表评论。

测试代码与任何其他代码一样,应该进行维护和重构。

这意味着如果您有共享逻辑,则将其提取到自己的函数。

某些unit testing库(如xUnit系列)具有此类共享代码的特定测试夹具,设置和拆卸属性。

看到这个相关的问题 – “为什么复制粘贴代码很危险?”。

复制粘贴没有问题,这是一个很好的起点。 实际上,它比从头开始更好,就好像你有工作代码(无论是测试还是其他方式),然后复制粘贴比从头开始更可靠,也更快。

然而,这只是第1步。第2步是重构共性,第1步只是为了帮助你看到这种共性。 如果您已经可以在没有复制的情况下清楚地看到它(有时它更容易先复制然后检查,有时它不是,并且它取决于执行此操作的人),然后跳过步骤1。

如果您要重复代码,那么您必须重构。 您的情况是一个常见问题,可以使用“参数测试”解决。 测试工具支持时的参数测试允许将多组输入值作为参数传递。 您可能还想查找Fuzz测试,我发现它在这种情况下很有用。

请记住,您的测试正在推动您的代码。 如果你发现你的测试看起来重复,除了左/右之类的东西,那么也许有一些左右复制的底层代码。 因此,您可能希望查看是否可以重构代码以使用左侧或右侧并向其发送左侧或右侧标志。

我同意@Rob。 代码需要重构。 但是如果你不想在这个时候重构代码那么你就可以进行参数化测试了。 针对不同参数运行相同的测试。 请参阅nunit中的TestCaseTestCaseSource属性。

请参阅http://nunit.org/index.php?p=parameterizedTests&r=2.5

xunitpatterns.org网站上写着“不”(复制/粘贴不正常),因为在需要更新测试时会增加成本:

  • 测试代码重复

“剪切和粘贴”是一种用于快速编写代码的强大工具,但它会生成相同代码的许多副本,每个副本必须并行维护。

为了进一步阅读它还链接到文章

  • 重构测试代码

作者:Arie van Deursen,Leon Moonen,Alex van den Bergh,Gerard Kok

我有时发现自己只是为了避免测试代码重复而进行非常复杂的unit testing。 我认为这样做并不好。 任何单个unit testing都应尽可能简单。 如果你需要一个重复来实现它 – 让它成为现实。

另一方面,如果你的unit testing有+100500行代码,那么它显然应该被重构,这将是一个简化。

当然,尝试避免无意义的unit testing重复,例如测试1 + 1 = 2,2 + 2 = 4,3 + 3 = 6。 如果您确实需要在不同数据上测试相同的方法,请编写数据驱动的测试。