我的数据访问层中有一个执行映射的方法。该方法接受DataReader,并将数据映射到正确的域对象属性。有没有办法以某种方式模拟DataReader,这样我就可以对映射方法执行单元测试而不会遇到物理数据库?
答案 0 :(得分:11)
幸运的是,DataReader
实现了IDataReader
界面。
不要依赖代码中的DataReader
,而是使用IDataReader
。然后,在测试中,您可以替换自己的返回虚拟数据的实现,或者使用类似Rhino.Mocks或类似的模拟框架来创建存根并分配返回值。
根据您在代码中“获取”DataReader
的方式,您可能需要进行一些重构。你想要的是在构造函数(首选)或通过属性“注入”这样的外部依赖关系,以便类的使用者可以替换IDataReader
的任何实现。 (这种替换也是为什么你将参数/属性声明为抽象而不是具体类型的原因。)这被称为Dependency Injection,Inversion of Control的一种形式。
答案 1 :(得分:3)
是的,不要使用DataReader
,而是使用IDataReader或IDataRecord,然后模拟您想要的任何内容。
答案 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);
不是完整的证明方式,但有效。希望它有所帮助:)