【发布时间】:2016-06-15 18:55:40
【问题描述】:
问题/问题
我无法通过测试,因为 Generic Repository 类 this.dbSet = context.Set<T>(); 始终为 null。正如您在下面的代码中看到的,我已经模拟了DbSet 和上下文。我还设置了模拟上下文以返回模拟DbSet。 EnityRepository 构造函数按预期采用模拟的上下文,但 this.dbSet = context.Set<T>(); 没有接受我的模拟 DbSet。我不确定我做错了什么。我不是在用正确的方式嘲笑这个吗?
结构:
- DAL - 实体框架、通用存储库、工作单元
- BLL - 服务,自动映射器(将实体生成的类/对象映射到 业务对象)
-
接口 -
IService - 模型 - 业务对象
- Web - ASP.NET MVC
- 测试 - 单元测试
通用存储库
public class EntityRepository<T> : IEntityRepository<T> where T : class
{
internal MyDB_Entities context;
internal DbSet<T> dbSet;
public EntityRepository(MyDB_Entities context)
{
this.context = context;
this.dbSet = context.Set<T>();
}
public virtual T GetByID(object id)
{
return dbSet.Find(id);
}
// more code
}
通用存储库接口
public interface IEntityRepository<T> where T : class
{
IEnumerable<T> Get(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "");
T GetByID(object id);
// more code
}
工作单元
public class UnitOfWork : IUnitOfWork, IDisposable
{
MyDB_Entities _context;
public IEntityRepository<Customer> customerRepository { get; set; }
public IEntityRepository<Product> productRepository { get; set; }
public UnitOfWork(MyDB_Entities context)
{
_context = context;
customerRepository = new EntityRepository<Customer>(_context);
productRepository = new EntityRepository<Product>(_context);
}
public void Save()
{
_context.SaveChanges();
}
// more code
}
工作单元界面
public interface IUnitOfWork
{
IEntityRepository<Customer> customerRepository { get; set; }
IEntityRepository<Product> productRepository { get; set; }
void Dispose();
void Save();
}
服务
public class SomeService : ISomeService
{
readonly IUnitOfWork _unitOfWork;
public SomeService (IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
// DoSomethingMethod
}
服务接口
public interface ISomeService
{
// IDoSomethingMethod
}
扩展
public static class MockDBSetExtension
{
public static void SetSource<T>(this Mock<DbSet<T>> mockSet, IList<T> source) where T : class
{
var data = source.AsQueryable();
mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
}
}
测试类
[TestClass]
public class My_Test
{
Mock<DbSet<Product>> _mockProductDBSet;
Mock<MyDB_Entities> mockContext;
[TestInitialize]
public void TestInitialize()
{
_mockProductDBSet = new Mock<DbSet<Product>>();
mockContext = new Mock<MyDB_Entities>();
mockContext.Setup(s => s.Products).Returns(_mockProductDBSet.Object);
}
[TestMethod]
public void TestMocking()
{
var prod = new Product() { ProductName= "AAA", ProductID = 1 };
_mockProductDBSet.SetSource(new List<Product> { prod });
// more code here (new up the service, then test the service method, etc)
}
}
【问题讨论】:
-
被测系统是什么。因为根据您拥有的接口,如果被测系统仅引用接口,那么您无需模拟 DbSet 或 DbContext。它们没有被各自的接口公开。
-
在这一点上,我只是在测试之前尝试看看我是否可以模拟假数据/记录。我可以在服务类中放置一个方法调用作为我的 sut 和模型 IUnitOfWork 然后对其进行测试。这在理论上是可以做到的,我现在不太担心。我更担心能够模拟一些假记录......这似乎失败了=(
-
澄清一下 - 我的目标只是能够从产品存储库中调用 GetByID(1) 并能够看到我创建的假记录。您如何建议在不模拟上下文和数据库集的情况下进行测试?
标签: c# entity-framework unit-testing repository moq