你如何对DAL进行单元测试?

时间:2011-04-13 15:37:40

标签: unit-testing ado.net mocking dbproviderfactories

我的应用程序中有一个数据访问层,它包装了一个ADO.NET数据提供程序。 DAL将数据提供程序返回的数据转换为.NET对象。我已经看到很多帖子建议不要对DAL进行单元测试,但它让我担心在那里会出现很多问题 - 有很多循环,转换和空检查。

我对使用RhinoMocks之类的东西创建一个模拟DbProvider有一些想法,但是我在每个测试中必须模拟的接口数量将是压倒性的,并且我必须设置的期望数量将使得测试非常难以阅读。似乎每个测试都比它测试的代码更复杂 - 从单元测试的3个目标的角度来看,这将是一场灾难:

  1. 可读性
  2. 可维护性
  3. 可信
  4. 我有一个想法是实现一个友好的DbProviderFactory来从xml加载样本数据。我可以通过测试中的Dependency Injection将其插入。它应该使维护测试更加简单。一个简单的例子可能是:

    [TestCase]
    public void CanGetCustomer()
    {
        var expectedCommand = new XmlCommand("sp_get_customer");
        expectedCommand.ExpectExecuteDataReader(
            resultSet: @"<customer firstName=""Joe"" lastName=""Blogs"" ... />");
    
        var factory = new XmlProviderFactory(expectedCommand);
    
        var dal = new CustomerDal(factory);
        Customer customer = dal.GetCustomer();
    
        Assert.IsNotNull(customer, "The customer should never be null");
        Assert.AreEqual(
            "Joe", customer.FirstName, 
            "The customer had an unexpected FirstName.");
    }
    

    我认为这种方法 - 使用友好的DbProvider - 可能会更容易测试DAL代码。它具有以下优点:

    1. 测试数据将以xml格式显示,并且可以与单元测试一起放置在源代码管理中。它可以在外部文件中,也可以在测试中内嵌。
    2. 我没有使用真正的数据库,所以这消除了有状态问题。因此,我不必在每次测试之前将数据库置于已知状态。
    3. 我不必在每个测试中模拟所有ADO.NET接口。我将编写一组假实现,我可以在整个代码库中重复使用。
    4. 人们会对这个想法提出一些批评吗?我可以使用类似的实现吗?

      由于

1 个答案:

答案 0 :(得分:2)

我对数据访问类(DAL,DAC,DAO,存储库等)的正确单元测试(不,不是集成测试)的主题进行了很多哲学论证。有些人认为,由于您正在进行集成测试,因此毫无意义。我发现单元测试这些经常被忽略的代码单元具有巨大的价值。首先,为了正确地对数据访问类进行单元测试,它必须正确构造,并且必须在消费者可以交互的沙子中绘制线 - 想想接口。数据访问实现应该定义一个接口,它实现消费应用程序代码只依赖于它。您选择的基础结构代码(ADO.NET,NHibernate,NDatabase等)应该具有您的数据访问代码仅依赖的接口。通过正确使用和利用这些基础结构接口(IDBConnection,ISession,IDatabase等),您可以使用您选择的模拟工具在单元测试中模拟这些接口。这为您提供了更高质量的数据访问代码,这些代码经过了单元测试(模拟基础设施接口),集成测试(针对REAL数据库),并且具有较低的净耦合。

一个注意事项:在我看来,当数据访问相关代码流过数据访问(或持久性)层时,需要警惕的代码异味。例如,如果您看到连接,命令,会话等的使用高于数据访问类的实现,则会出现违反“关注点分离”的情况。