之前没有真正使用过多次单元测试,但是稍微阅读了一下,并且认为你真的应该一次测试一件事。但是,例如保存和检索对象时,如何以一种很好的方式执行此操作?我没有看到保存工作没有使用“检索”功能。并且无法在不保存的情况下测试检索。目前我尝试过这样的事情......我怎样才能确保我的测试可以知道哪一个不起作用?
[TestMethod]
public void TestSaveObject()
{
TestStorage storage = new TestStorage();
ObejctToSave s1 = new ObejctToSave {Name = "TEST1"};
ObejctToSave s2 = new ObejctToSave { Name = "TEST2" };
storage.SaveObject(s1);
storage.SaveObject(s2);
List<ObjectToSave> objects = storage.GetObjects();
Assert.AreEqual(2, objects.Count);
Assert.AreEqual("TEST1", objects[0].Name);
Assert.AreEqual("TEST2", objects[1].Name);
}
答案 0 :(得分:3)
你注意到自己单元测试应该一次测试一件事。然而,你在这里测试两件事 - 存储和检索。
如果要测试服务层以正确处理持久性,请模拟持久性对象(存储库),然后调用服务方法以添加对象 - 验证是否已调用存储库上的相应方法。检索也一样。
主要问题是:
您正在实施持久性库。如果是,您当然应该使用模拟对象来测试持久性方法,这些模拟对象会伪造OS调用文件系统操作。
您想测试持久性方法(如您的示例所示),但他们正在使用第三方库。它对unit-tests没有意义 - 这是integration testing发挥作用的部分。
简单地说 - 单元测试测试单个单元 - 代码的“模块”与其他模块分开。其他部分为mocked,目的是仅验证被测单元的代码。
另一方面,集成测试测试一组模块一起工作。通常集成测试用于测试整个系统的典型用例,有时它们仅用于对一组模块进行回归测试。有许多可能性,但重点是模块正在一起测试 - 因此集成。
答案 1 :(得分:1)
我喜欢使用它的反函数来测试一个函数 即使这意味着一次测试两件事,这可能是集成测试,而不是单元测试。
然而,我遇到了一些问题。
storage.GetObjects()
可能会以错误的顺序检索对象,因此尽管每个对象都是错误的,但您的测试可能会失败处理得当。这同样适用于具有子列表的对象。ObejctToSave
添加新属性并忘记更新相应的测试,则会出现误报 - ObejctToSave
告诉你成功,但新的财产没有得到妥善保存。对于dotnet中这些限制的解决方法,我做了这个
compare<t>(t object1, t object2, params string[] propertyNamesToBeIgnoredInTest)
,它使用反射来比较属性并在比较它们之前对子列表进行排序。答案 2 :(得分:0)
有趣的一点。我认为以最合适的TDD方式(它不应该是它应该的方式)来创建一个TestStorage模拟,并断言正确的调用是满足它的。因此,您可以为Save a Retrieve创建一个单独的测试,两者都具有模拟和适当的期望。