我需要从我的数据访问层单元测试内连接方法。
MY DAL看起来像这样:
public class MyDAL:IMyDAL
{
private MyContext context;
public MyDAL(MyContext Context)
{
this.context = Context;
}
public IEnumerable <Parent> Read(int childId)
{
var query = from parent in context.Parent
join child in context.Child on parent.Id equals child.Id
where child.Id == childId
select env;
return query.ToList();
}
我希望通过模拟Entity框架对Read方法进行单元测试,并遵循此链接http://msdn.microsoft.com/en-us/data/dn314429.aspx。
[TestMethod]
public void ReadMethod()
{
var data = new List<Parent>
{
new Parent { Id = 20 },
}.AsQueryable();
var data2 = new List<Child>
{
new Child { Id = 8 },
}.AsQueryable();
var mockSetPar = new Mock<DbSet<Parent>>();
var mockSetChild = new Mock<DbSet<Child>>();
mockSetPar.As<IQueryable<Parent>>().Setup(m => m.Provider).Returns(data.Provider);
mockSetPar.As<IQueryable<Parent>>().Setup(m => m.Expression).Returns(data.Expression);
mockSetPar.As<IQueryable<Parent>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSetPar.As<IQueryable<Parent>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
moockSetChild.As<IQueryable<Child>>().Setup(m => m.Provider).Returns(data2.Provider);
mockSetChild.As<IQueryable<Child>>().Setup(m => m.Expression).Returns(data2.Expression);
mockSetChild.As<IQueryable<Child>>().Setup(m => m.ElementType).Returns(data2.ElementType);
mockSetChild.As<IQueryable<Child>>().Setup(m => m.GetEnumerator()).Returns(data2.GetEnumerator());
var customDbContextMock = new Mock<MyContext>();
customDbContextMock.Setup(x => x.Parent).Returns(mockSetPar.Object);
customDbContextMock.Setup(x => x.Child).Returns(mockSetChild.Object);
var myDAL = new MyDAL(customDbContextMock.Object);
var actual = myDAL.Read(8);
Assert.IsNotNull(actual);
结果实际为空,因为尚未模拟连接方法,因此它不返回任何内容。
如何模拟join方法以返回值?
谢谢
答案 0 :(得分:2)
我想您已经注意到,模拟EF查询既耗时又脆弱。我的建议 - 不要嘲笑它。您可以在存储库接口下隐藏尽可能多的数据访问逻辑,这很容易模拟:
public interface IParentRepository
{
IEnumerable<Parent> GetParentsOfChild(int childId);
}
然后测试看起来像:
[TestMethod]
public void ReadMethod()
{
int childId = // get sample id
var expected = // get sample parents
var repositoryMock = new Mock<IParentRepository>();
repositoryMock.Setup(r => r.GetParentsOfChild(childId))
.Returns(expected);
var myDAL = new MyDAL(repositoryMock.Object);
var actual = myDAL.Read(childId);
repositoryMock.VerifyAll();
CollectionAssert.AreEqual(actual, expected);
}
如果要验证查询实现,那么最好的方法是接受/集成测试,它涉及真正的数据库。请记住 - 分析生成的IQueryable不足以确保您的查询在真实环境中有效。例如。您可以将运算符Last()
与IQueryable一起使用,但此查询将无法由实体框架转换为SQL。
答案 1 :(得分:2)
数据库交互的内存中测试可能会产生误导,因为LINQ to Entities功能是LINQ to Objects功能的子集,因此您可以编写一个绿色的测试,但查询将始终在生产中引发异常。 / p>
这在单一概念层面上也是错误的。 DAL是一个代码,它存在于两个系统的边界上 - app和db。它的责任是整合它们。因此,如果您将这些集成组件隔离开来,那么您的测试将变得毫无意义,因为它会削弱SUT的核心职责。
要测试查询逻辑,您必须使用与生产类似的数据库提供程序。所以你需要集成测试。 =一个有用的解决方案是使用SQLite内存数据库。它将在实体框架涵盖的大多数场景中表现为真实数据库,但其性能几乎与单元测试中基于内存中集合的模拟一样快。
如果您愿意,可以将SQLite视为类固醇的数据库模拟。