如何模拟DataReader以进行单元测试DAL

时间:2010-08-26 18:52:29

标签: c#

我的数据访问层中有一个执行映射的方法。该方法接受DataReader,并将数据映射到正确的域对象属性。有没有办法以某种方式模拟DataReader,这样我就可以对映射方法执行单元测试而不会遇到物理数据库?

3 个答案:

答案 0 :(得分:11)

幸运的是,DataReader实现了IDataReader界面。

不要依赖代码中的DataReader,而是使用IDataReader。然后,在测试中,您可以替换自己的返回虚拟数据的实现,或者使用类似Rhino.Mocks或类似的模拟框架来创建存根并分配返回值。

根据您在代码中“获取”DataReader的方式,您可能需要进行一些重构。你想要的是在构造函数(首选)或通过属性“注入”这样的外部依赖关系,以便类的使用者可以替换IDataReader的任何实现。 (这种替换也是为什么你将参数/属性声明为抽象而不是具体类型的原因。)这被称为Dependency InjectionInversion of Control的一种形式。

答案 1 :(得分:3)

是的,不要使用DataReader,而是使用IDataReaderIDataRecord,然后模拟您想要的任何内容。

答案 2 :(得分:3)

如果您想模拟IDataReader以返回记录列表,您可以创建一个实现IDataReader的类并覆盖其某些方法(如Read()和Indexer)。此外,您需要一个变量来记录当前行和一个变量来保存列表值。以下是执行此操作的示例代码:

public class MockDataReader : IDataReader
{
    private int _rowCounter = 0;
    private List<Dictionary<string,object>> _records = new List<Dictionary<string,object>>();

    public MockDataReader(List<Dictionary<string,object>> records)
    {
        _records = records;
    }

    public bool Read()
    {
        _rowCounter++;
        if (_rowCounter < _records.Count) return true;
        return false;
    }

    public object this[string name]
    {
        get { return _records[_rowCounter][name]; }
    }
}

然后,要使用此类,您可以使用以下代码:

var itemsList = new List<Dictionary<string, object>>();
for (int i = 0; i < 5; i++)
{
    var num = i + 1;
    var items = new Dictionary<string, object>();
    items.Add("Id", num);
    items.Add("FirstName", "MyFirstName" + num);
    items.Add("LastName", "MyLastName" + num);
    itemsList.Add(items);
}


var result = new MockDataReader(itemsList); 

不是完整的证明方式,但有效。希望它有所帮助:)