单元测试复杂相互作用的正确方法

时间:2009-11-02 20:33:06

标签: unit-testing frameworks

我必须开始使用QualityTools.UnitTestFramework为我们开发的Web服务层编写一些单元测试,当我的方法从一开始就看起来不正确时。

单元测试似乎应该能够以任何顺序运行而不依赖于其他测试。

我最初的想法是使用类似于以下测试的内容(简化的示例),它将以相同的顺序作为有序测试运行。

AddObject1SuccessTest
AddObject2WithSameUniqueCodeTest
(依赖首先创建了object1的测试,然后期望失败)
AddObject2SuccessTest
UpdateObject2WithSameUniqueCodeTest
(依赖于先创建了object1的第一个测试,第一个创建了object2的thrid测试然后期望失败)
UpdateObject2SuccessTest
GetObjectListTest
DeleteObjectsTest
(使用添加的ID)

但是,测试之间没有状态,并且没有明显的方法将例如添加的ID传递给deletetest。

那么,那么单元测试复杂交互的正确方法是否适用于场景?

例如

AddObjectSuccessTest
(创建一个对象,让它验证数据,然后删除它)
AddObjectWithSameUniqueCodeTest
(创建对象1然后尝试创建具有失败的对象2,然后删除对象1)
UpdateObjectWithSameUniqueCodeTest
(创建对象1然后创建对象2,然后尝试更新对象2以使其具有与失败时对象1相同的唯一代码,然后删除对象1和对象2)

我是在做错了吗?

由于

2 个答案:

答案 0 :(得分:5)

单元测试的宗旨是每个测试用例应独立于任何其他测试用例。 MSTest(以及所有其他单元测试框架)通过不保证运行测试的顺序来强制执行此操作 - 有些(xUnit.NET)甚至可以在每次测试运行之间随机化顺序。

建议的最佳做法是将单位简化为简单的交互。虽然不能提供严格的规则,但如果交互过于复杂,则不是单元测试。在任何情况下,复杂的测试都很脆弱并且具有非常高的维护开销,这就是为什么简单的测试是首选。

听起来你的测试之间存在共享状态。这导致相互依赖的测试,应该避免。相反,您可以编写可重用的代码,为每个测试设置前置条件状态,确保此状态始终正确。

这种先决条件状态称为夹具。书籍xUnit Test Patterns包含许多关于如何在许多不同场景中管理灯具的信息和指导。

答案 1 :(得分:3)

作为Mark所说的补充,是的,每个测试应该完全独立于其他测试,并且,要使用您的术语,每个测试应该是一个独立的场景,可以独立于其他场景运行。 /> 我假设您正在描述您正在测试持久性,因为您已经在步骤中删除了在测试结束时创建的实体,以清理状态。理想情况下,单元测试完全在内存中运行,每个测试之间没有共享状态。实现这一目标的一种方法是使用Mocks。我假设你有类似Repository的东西,所以你的类调用Repository.Add(myNewObject),它调用Repository.ValidateObjectCanBeAdded(myNewObject)之类的东西。而不是测试真实存储库,它将在数据库中添加对象并需要删除它们以在测试后清理状态,您可以使用两种相同的方法创建一个接口IRepository,并使用模拟检查当您class调用IRepository,它正在以正确的顺序使用正确的参数来运用正确的方法。它还使您能够在内存中将“假”存储库设置为您想要的任何状态,而无需在实际存储中物理添加或删除记录。
希望这有帮助!