单元测试和数据库

时间:2010-06-26 13:47:49

标签: c# unit-testing mocking maintainability

This question about unit tests引发了另一件困扰我的事情。在点击数据库时,我经常以三种方式进行单元测试。

  1. 创建模拟对象并将其插入。这样做的好处是不需要数据库,但这很耗时,而且我不确定我获得了多少投资回报。我已经进入了IOC和moq一点点,但它仍然看起来很痛苦。
  2. 创建设置和拆卸数据库脚本以创建已知案例,并对其进行测试。同样,可能是时间密集的,但大多数时候仍然比模拟对象更容易创建。其他工作人员仍然可以运行它,假设他们的localhost上有SQL服务器。
  3. 手动检查开发人员数据库并修改单元测试。密集手动工作,但如果我有一个不改变的“测试集”,它似乎工作正常。在我的机器上,至少:-)。
  4. 我知道选项1是进行单元测试的“正确”方式,但在三者中,这可能是我用过的最少的选项(虽然最新的项目已经与IOC一起使用,所以门对我开放)。我意识到这很大程度上取决于被嘲笑的内容和正在测试的内容,但我在这里缺少什么?

    如果上下文有帮助,我在C#商店,编写内部应用程序,只有少数开发人员。

4 个答案:

答案 0 :(得分:3)

如果您的数据访问层只暴露少数IQueryable<T>方法,那么第一个应该不会那么难。您可以使用一个很好的技巧来伪造数据:只需将实体对象存储在List<T>中并使用AsQueryable。我觉得这比数据部分的moq更容易。

关于国际奥委会,我认为它目前过度使用(请注意,我的意见代表了这方面的少数程序员)。您可以在测试期间使用Moles之类的工具进行模拟,而不必滥用您的程序设计。除非设计实际上要求它,否则我不使用IOC。

答案 1 :(得分:2)

我肯定会继续使用真正的单元测试(选项1)。我喜欢斯蒂芬对此的建议。

您也可以使用实际数据库(选项2)必需进行集成测试(选项2)。为什么?因为您需要测试的部分内容(O / R映射,与实际DB模式的兼容性等)不在真正的单元测试中。

至于设置和拆卸逻辑,继承此通常就足够了(对数据库使用.NET,NUnit和SqlServer):

using System.Transactions;
using NUnit.Framework;
namespace Crown.Util.TestUtil
{
    [TestFixture]
    public class PersistenceTestFixture
    {
        public TransactionScope TxScope { get; private set; }

        [SetUp]
        public void SetUp()
        {
            TxScope = new TransactionScope();
        }

        [TearDown]
        public void TearDown()
        {
            if (TxScope != null)
            {
                TxScope.Dispose();
                TxScope = null;
            }
        }
    }
}

很容易就是馅饼。

答案 2 :(得分:1)

对此有一整套答案。首先要做的是清楚地表达您正在测试的内容。它是一个API的外观,它背后有一个数据库,DAO对象,你的数据库结构?

实现这一目标也有助于您确定测试方法的最佳方法。从我所看到的还有你所列出的替代品。这是在内存数据库(如hsql)中启动并运行您的类和测试。这意味着您可以在测试开始时创建数据库结构。因为它在内存中你不必担心拥有数据库服务器,它很快,你可以用特定于你的测试的数据加载它。

我使用模拟器很多,虽然它们非常适合单元测试一个类,但在某些情况下它们不是。他们也很容易错过铅。对于与模拟一起工作的东西,在集成时不起作用的情况并不少见。这样做的原因是你正在加载带有某些期望和响应的模拟,你可能从模拟所代表的东西中错误地解释了它。

别误会我的意思,我喜欢嘲笑并使用它们。但是这样做你必须永远不要假设因为某些东西经过单元测试,这是正确的。它确实增加了机会,但在集成测试中实际上给你100%的保证。

答案 3 :(得分:0)

你真正测试的是什么让你觉得这很难?

如果您将业务和服务层逻辑与持久性代码分离,您应该能够轻松地隔离要进行单元测试的代码,而无需使用数据库。

单元测试最重要的原则之一是单独解耦和测试。当您清楚地了解如何执行此操作时,单元测试很容易。如果不这样做,单元测试就会变得很难。