单元测试 - 存根 SqlDataReader

Posted

技术标签:

【中文标题】单元测试 - 存根 SqlDataReader【英文标题】:Unit testing - stubbing an SqlDataReader 【发布时间】:2012-04-12 02:39:35 【问题描述】:

我们有一个从 SQL Server 提取数据的 n 层 Web 应用程序。我们的数据访问逻辑返回一个 SqlDataReader,其数据随后用于创建我们的业务对象(也称为数据传输对象)。

我们希望构建单元测试来检查我们的代码,这些代码解释这些 SqlDataReader 对象返回的数据以构建我们的业务对象。

因此,似乎有必要在单元测试期间构建存根来替换 SqlDataReader 对象。可能相当典型的是,我们的 SqlDataReader 对象通常返回多个记录集,每个记录集包含多行。

    这是一项明智的努力吗? 我们应该如何构建这些存根对象?

在此先感谢

格里夫

【问题讨论】:

【参考方案1】:

自动化测试基本上总是一项明智的努力:)

能够对此进行测试的第一步是让数据访问逻辑返回 IDataReader 而不是 SqlDataReader - SqlDataReader 实现 IDataReader,所以没有问题。

在您的单元测试中,您可以手动构建和填充DataTable 对象,并调用dataTable.CreateDataReader() 以获取IDataReader 以传递给被测对象。

编辑

要为您的测试提供一组示例数据,我建议您为使用的每个数据表使用ObjectMother,将数据表的创建保存在一个专用位置。然后,您可以将方法放在每个 ObjectMethod 类上,以以强类型的方式更新某些数据。例如:

public class PersonalDetailsBuilder

    private DataTable _dataTable;

    public PersonalDetailsBuilder CreateNewTable()
    
        this._dataTable = new DataTable("CustomerPersonalDetails")
        
            Columns = 
            
                new DataColumn("CustomerId", typeof(int)),
                new DataColumn("CustomerName", typeof(string))
            
        ;

        return this;
    

    public PersonalDetailsBuilder AddStandardData(int numberOfRows = 3)
    
        foreach (int i in Enumerable.Range(1, numberOfRows + 1))
        
            this.AddRow(i, "Customer " + i);
        

        return this;
    

    public PersonalDetailsBuilder AddRow(int customerId, string customerName)
    
        this._dataTable.Rows.Add(customerId, customerName);

        return this;
    

    public IDataReader ToDataReader()
    
        return this._dataTable.CreateDataReader();
    

...然后您可以像这样使用它来获取数据读取器:

IDataReader customerDetailsReader = new PersonalDetailsBuilder()
    .CreateNewTable()
    .AddStandardData()
    .AddRow(17, "Customer 17")
    .ToDataReader();

【讨论】:

想象我们的 IDataReader 对象之一返回有关客户的详细信息: rs1 = 个人详细信息; rs2 = 权限; rs3 - xxx 等。大多数测试将使用它作为默认数据集。某些测试可能希望使用这些值中的大部分,但会覆盖数据表中的某些属性。这有多容易?几乎像继承...... 我不确定我是否理解 - 您是指用于多个结果集的单个数据读取器,还是一组数据读取器?无论如何,我已经更新了我的答案。 @DrGriff 你可能想要包含一个重载到AddStandardData,它有一个Action<DataRowCollection> 类型的参数;在您的重载方法中,您将调用原始的AddStandardData 方法,然后执行操作,并传入this._DataTable.Rows 属性。然后,您可以在操作中操作数据表中行的内容。

以上是关于单元测试 - 存根 SqlDataReader的主要内容,如果未能解决你的问题,请参考以下文章

单元测试术语的概述(存根与模拟,集成与交互)?

《单元测试的艺术》读书笔记----使用存根破除依赖

扩展特征的单元测试类 - 我如何在特征中模拟和存根方法?

存根 Google Maps/Places iOS SDK 调用以进行单元测试

GAE的存根(用于单元测试)

无论存根权限如何,带有 checkPermission 的 Apache shiro 单元测试都会通过