单元测试保存/检索对象

时间:2014-01-12 09:50:13

标签: c# unit-testing

之前没有真正使用过多次单元测试,但是稍微阅读了一下,并且认为你真的应该一次测试一件事。但是,例如保存和检索对象时,如何以一种很好的方式执行此操作?我没有看到保存工作没有使用“检索”功能。并且无法在不保存的情况下测试检索。目前我尝试过这样的事情......我怎样才能确保我的测试可以知道哪一个不起作用?

    [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);
    }

3 个答案:

答案 0 :(得分:3)

你注意到自己单元测试应该一次测试一件事。然而,你在这里测试两件事 - 存储和检索。

如果要测试服务层以正确处理持久性,请模拟持久性对象(存储库),然后调用服务方法以添加对象 - 验证是否已调用存储库上的相应方法。检索也一样。

主要问题是:

  • 您正在实施持久性库。如果是,您当然应该使用模拟对象来测试持久性方法,这些模拟对象会伪造OS调用文件系统操作。

  • 您想测试持久性方法(如您的示例所示),但他们正在使用第三方库。它对unit-tests没有意义 - 这是integration testing发挥作用的部分。

简单地说 - 单元测试测试单个单元 - 代码的“模块”与其他模块分开。其他部分为mocked,目的是仅验证被测单元的代码。

另一方面,集成测试测试一组模块一起工作。通常集成测试用于测试整个系统的典型用例,有时它们仅用于对一组模块进行回归测试。有许多可能性,但重点是模块正在一起测试 - 因此集成

答案 1 :(得分:1)

我喜欢使用它的反函数来测试一个函数  即使这意味着一次测试两件事,这可能是集成测试,而不是单元测试。

然而,我遇到了一些问题。

    列表的
  • 排序顺序 false negative :在您的示例中,storage.GetObjects()可能会以错误的顺序检索对象,因此尽管每个对象都是错误的,但您的测试可能会失败处理得当。这同样适用于具有子列表的对象。
  • 维持此测试:如果您向ObejctToSave添加新属性并忘记更新相应的测试,则会出现误报 - ObejctToSave告诉你成功,但新的财产没有得到妥善保存。

对于dotnet中这些限制的解决方法,我做了这个

  • 使用nbuilder库自动为每个属性分配可重现值,以便自动测试新属性
  • 创建了一个自定义对象比较方法compare<t>(t object1, t object2, params string[] propertyNamesToBeIgnoredInTest),它使用反射来比较属性并在比较它们之前对子列表进行排序。

答案 2 :(得分:0)

有趣的一点。我认为以最合适的TDD方式(它不应该是它应该的方式)来创建一个TestStorage模拟,并断言正确的调用是满足它的。因此,您可以为Save a Retrieve创建一个单独的测试,两者都具有模拟和适当的期望。