首先,方法实现不依赖于NpgsqlDataReader的具体实现。因此,您可以将签名更改为:
public static T ToEntity<T>(this IDataReader reader) where T : new()
其次,签名不符合逻辑。数据读取器用于在结果集上循环,并生成
列表
行(包含0、1或更多元素),而不是单个结果。因此,更符合逻辑的签名和实现应该是:
public static IEnumerable<T> ToEntity<T>(this IDataReader reader) where T : new()
{
var properties = typeof(T).GetProperties();
while (reader.Read())
{
var result = new T();
foreach (var prop in properties)
{
for (var i = 0; i < reader.FieldCount; i++)
{
if (reader.GetName(i).Replace("_", "").Equals(prop.Name, StringComparison.InvariantCultureIgnoreCase))
{
var val = reader.GetValue(i) != DBNull.Value ? reader.GetValue(i) : null;
prop.SetValue(result, val);
}
}
}
yield return result;
}
}
现在您可以提供IDataReader的伪实现。或者你可以使用一个模拟框架,比如NSubstitute,但是如果你是单元测试的新手,一个更简单的方法是手动实现一个。例如
in this gist (incomplete implementation)
我在内存泛型列表上实现了IDataReader(以及便于使用的扩展方法)。
现在,您可以编写这样的测试方法:
// note the anonymous type here
var expectedEntity = new {MY_PROPERTY = "SomeValue"};
var reader = new[]
{
expectedEntity
}.AsDataReader();
var entity = reader.ToEntity<MyEntity>().First();
Assert.AreEqual("SomeValue", entity.MyProperty);
最后,使用反射的解决方案有效,但最终可能会很慢。请记住,这种代码是一个已解决的问题;看看轻量的ORM,如PetaPoco,整洁。净资产。