C# Moq和Include的单元测试问题(EF6)
我已经做了相当多的研究,并尝试了各种不同的方式让考试通过,但现在我需要一些帮助 我正在尝试测试以下存储库方法: 上下文如下所示:C# Moq和Include的单元测试问题(EF6),c#,entity-framework,mocking,nunit,moq,C#,Entity Framework,Mocking,Nunit,Moq,我已经做了相当多的研究,并尝试了各种不同的方式让考试通过,但现在我需要一些帮助 我正在尝试测试以下存储库方法: 上下文如下所示: public interface IAuthDbContext : IDbContextBase { } public interface IDbContextBase { IDbSet<T> Set<T>() where T : class; IEnumerable<DbValidationError> Get
public interface IAuthDbContext : IDbContextBase
{
}
public interface IDbContextBase
{
IDbSet<T> Set<T>() where T : class;
IEnumerable<DbValidationError> GetEntityValidationErrors();
int SaveChanges();
Task<int> SaveChangesAsync();
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}
protected override void GivenThat()
{
var mockRolesSet = GetMockDbSet(PortalRoles().AsQueryable());
mockRolesSet.Setup(x => x.Include("PortalRole")).Returns(mockRolesSet.Object);
var mockDomainsSet = GetMockDbSet(PortalDomains().AsQueryable());
mockDomainsSet.Setup(x => x.Include("PortalDomain")).Returns(mockDomainsSet.Object);
var mockPortalDomanRolesSet = GetMockDbSet(PortalDomainRoles().AsQueryable());
mockPortalDomanRolesSet.Setup(x => x.Include("PortalRole")).Returns(mockPortalDomanRolesSet.Object);
mockPortalDomanRolesSet.Setup(x => x.Include("PortalDomain")).Returns(mockPortalDomanRolesSet.Object);
var customDbContextMock = new Mock<IAuthDbContext>();
customDbContextMock.Setup(x => x.Set<PortalRole>()).Returns(mockRolesSet.Object);
customDbContextMock.Setup(x => x.Set<PortalDomain>()).Returns(mockDomainsSet.Object);
customDbContextMock.Setup(x => x.Set<PortalDomainRole>()).Returns(mockPortalDomanRolesSet.Object);
ClassUnderTest = new PortalsRepository(customDbContextMock.Object);
}
我的单元测试设置如下所示:
public interface IAuthDbContext : IDbContextBase
{
}
public interface IDbContextBase
{
IDbSet<T> Set<T>() where T : class;
IEnumerable<DbValidationError> GetEntityValidationErrors();
int SaveChanges();
Task<int> SaveChangesAsync();
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}
protected override void GivenThat()
{
var mockRolesSet = GetMockDbSet(PortalRoles().AsQueryable());
mockRolesSet.Setup(x => x.Include("PortalRole")).Returns(mockRolesSet.Object);
var mockDomainsSet = GetMockDbSet(PortalDomains().AsQueryable());
mockDomainsSet.Setup(x => x.Include("PortalDomain")).Returns(mockDomainsSet.Object);
var mockPortalDomanRolesSet = GetMockDbSet(PortalDomainRoles().AsQueryable());
mockPortalDomanRolesSet.Setup(x => x.Include("PortalRole")).Returns(mockPortalDomanRolesSet.Object);
mockPortalDomanRolesSet.Setup(x => x.Include("PortalDomain")).Returns(mockPortalDomanRolesSet.Object);
var customDbContextMock = new Mock<IAuthDbContext>();
customDbContextMock.Setup(x => x.Set<PortalRole>()).Returns(mockRolesSet.Object);
customDbContextMock.Setup(x => x.Set<PortalDomain>()).Returns(mockDomainsSet.Object);
customDbContextMock.Setup(x => x.Set<PortalDomainRole>()).Returns(mockPortalDomanRolesSet.Object);
ClassUnderTest = new PortalsRepository(customDbContextMock.Object);
}
我的单元测试支持方法:
当单元测试执行有问题的方法时,我得到:
System.NullReferenceException:对象引用未设置为对象的实例
很可能它不知道如何处理嵌套的include语句-我已经学习了许多在线问题和教程,现在我陷入了困境。我的答案可能有点争议,但根据我的经验,测试存储库层或任何你称之为实际数据访问代码的最佳方法,就是让它在测试过程中调用数据库 在编写单元测试时,您假设实体框架以特定的方式工作。但有时它的工作方式与您预期的不同,因此测试可能会通过,即使代码不能正常工作 举个例子,这说明了我使用的上一个EF版本是版本4的问题,但我假设我的声明对于EF6仍然是正确的
public class Foo {
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public bool Active {
get { return StartDate < DateTime.Now && EndDate > DateTime.Now }
}
}
public class FooRepository {
public IEnumerable<Foo> ActiveFoos { get { return DataContext.Foos.Where(x => x.Active) } }
}
针对模拟数据访问测试此FooRepository将通过,但针对真实数据库执行将引发异常。这是因为EF将尝试为Wherex=>x.Active创建一个SQL子句,但由于Active不是数据库中的字段,EF将不知道如何将查询转换为SQL
所以你的单元测试提供了一个假阳性。对数据库执行测试将使其失败,这是应该的