.net core 使用AutoMapper ProjectTo和Moq.EntityFrameworkCore进行单元测试
我有一些类通过依赖注入接收DbContexts,我想测试它们。我使用AutoMapper的ProjectTo,因为我的实体通常比我从类返回的对象(dto)大得多。我真的很喜欢让AutoMapper调整我的查询,以便它只选择DTO中的字段 我一直在尝试使用Moq.EntityFrameworkCore来模拟我的DbContext。它工作得相对较好,但确实会导致AutoMapper ProjectTo()出现问题。我最终患上了残疾 显然,我对“测试AutoMapper”或我的DbContext不感兴趣,我只想测试我的代码。但是,我无法测试我的代码,因为它在投影上崩溃了 这是一个极简主义的复制,使用AutoFixture将代码缩短了一点,我将所有内容都放到了一个文件中,这样任何人都可以轻松地自己尝试:.net core 使用AutoMapper ProjectTo和Moq.EntityFrameworkCore进行单元测试,.net-core,automapper,moq,xunit,.net Core,Automapper,Moq,Xunit,我有一些类通过依赖注入接收DbContexts,我想测试它们。我使用AutoMapper的ProjectTo,因为我的实体通常比我从类返回的对象(dto)大得多。我真的很喜欢让AutoMapper调整我的查询,以便它只选择DTO中的字段 我一直在尝试使用Moq.EntityFrameworkCore来模拟我的DbContext。它工作得相对较好,但确实会导致AutoMapper ProjectTo()出现问题。我最终患上了残疾 显然,我对“测试AutoMapper”或我的DbContext不感兴
使用AutoFixture;
使用AutoFixture.AutoMoq;
使用自动制版机;
使用Microsoft.EntityFrameworkCore;
使用最小起订量;
使用Moq.EntityFrameworkCore;
使用System.Collections.Generic;
使用System.Threading.Tasks;
使用Xunit;
命名空间UnitTestEFMoqProjectTo
{
公共类MyBusinessFixture
{
私人IFixture_固定装置;
公共设施
{
_夹具=新夹具()
.自定义(新的AutoMoqCustomization());
var mockMapper=新的映射配置(cfg=>
{
AddProfile(新的MappingProfile());
});
var mapper=mockMapper.CreateMapper();
_fixture.Register(()=>mapper);
}
[事实]
公共异步任务DoSomething_with mock和projectto_ValidatesMyLogic()
{
//安排
var mockContext=new Mock();
mockContext.Setup(x=>x.myenties).ReturnsDbSet(新列表(_fixture.CreateMany(10));
_fixture.Register(()=>mockContext.Object);
var business=_fixture.Create();
//表演
待办公事;
//断言
断言。真(真);
}
}
公共类MyDbContext:DbContext
{
公共虚拟数据库集myenties{get;set;}
}
公共类MyEntity
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共字符串SomeProperty{get;set;}
公共字符串SomeOtherProperty{get;set;}
}
公共类MyDto
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
公共接口IMyBusiness
{
任务DoSomething();
}
公共类MyBusiness:IMyBusiness
{
私有只读MyDbContext\u MyDbContext;
专用只读IMapper\u映射器;
公共MyBusiness(MyDbContext MyDbContext,IMapper映射器)
{
_myDbContext=myDbContext;
_映射器=映射器;
}
公共异步任务DoSomething()
{
//我的程序的逻辑在这里,我想测试。
//查询投影和枚举
var projectedEntities=await _mapper.ProjectTo(_myDbContext.MyEntities.ToListAsync();
//这里是我的程序的一些逻辑,我想测试一下。
}
}
公共类映射配置文件:配置文件
{
公共映射配置文件()
{
CreateMap();
}
}
}
应输出以下错误:
Message:
System.InvalidCastException : Unable to cast object of type 'Moq.EntityFrameworkCore.DbAsyncQueryProvider.InMemoryAsyncEnumerable`1[UnitTestEFMoqProjectTo.MyEntity]' to type 'System.Linq.IQueryable`1[UnitTestEFMoqProjectTo.MyDto]'.
Stack Trace:
ProjectionExpression.ToCore[TResult](Object parameters, IEnumerable`1 memberPathsToExpand)
ProjectionExpression.To[TResult](Object parameters, Expression`1[] membersToExpand)
Extensions.ProjectTo[TDestination](IQueryable source, IConfigurationProvider configuration, Object parameters, Expression`1[] membersToExpand)
Mapper.ProjectTo[TDestination](IQueryable source, Object parameters, Expression`1[] membersToExpand)
MyBusiness.DoSomething() line 79
MyBusinessFixture.DoSomething_WithMocksAndProjectTo_ShouldMap() line 39
你知道我如何继续使用AutoMapper进行预测,同时让单元测试工作吗
以下是我的项目文件内容供参考:
netcoreapp3.1
全部的
运行时间;建设;本地人;内容文件;分析仪;可传递的
前几天我遇到了类似的问题,但最终我能够运行我的单元测试
我使用MockQueryable.Moq
()来模拟DBSet
,您可能应该试试这个包,因为可能存在问题
所以我的代码看起来像:
public class Project
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ProjectDto
{
public int Id { get; set; }
public string Name { get; set; }
}
class GetProjectsHandler : IRequestHandler<GetProjectsRequest, GetProjectsResponse>
{
private readonly IMyDbContext context;
private readonly IMapper mapper;
public GetProjectsHandler(
IMyDbContext context,
IMapper mapper)
{
this.context = context;
this.mapper = mapper;
}
public async Task<GetProjectsResponse> Handle(GetProjectsRequest request, CancellationToken cancellationToken)
{
IReadOnlyList<ProjectDto> projects = await context
.Projects
.ProjectTo<ProjectDto>(mapper.ConfigurationProvider)
.ToListAsync(cancellationToken);
return new GetProjectsResponse
{
Projects = projects
};
}
}
公共类项目
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
公共类项目
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
类GetProjectsHandler:IRequestHandler
{
私有只读IMyDbContext上下文;
专用只读IMapper映射器;
公共GetProjectsHandler(
IMyDbContext上下文,
IMapper(映射器)
{
this.context=上下文;
this.mapper=mapper;
}
公共异步任务句柄(GetProjectsRequest请求、CancellationToken CancellationToken)
{
IReadOnlyList项目=等待上下文
.项目
.ProjectTo(mapper.ConfigurationProvider)
.ToListSync(取消令牌);
返回新的GetProjectsResponse
{
项目=项目
};
}
}
简化单元测试如下所示:
public class GetProjectsTests
{
[Fact]
public async Task GetProjectsTest()
{
var projects = new List<Project>
{
new Project
{
Id = 1,
Name = "Test"
}
};
var context = new Mock<IMyDbContext>();
context.Setup(c => c.Projects).Returns(projects.AsQueryable().BuildMockDbSet().Object);
var mapper = new Mock<IMapper>();
mapper.Setup(x => x.ConfigurationProvider)
.Returns(
() => new MapperConfiguration(
cfg => { cfg.CreateMap<Project, ProjectDto>(); }));
var getProjectsRequest = new GetProjectsRequest();
var handler = new GetProjectsHandler(context.Object, mapper.Object);
GetProjectsResponse response = await handler.Handle(getProjectsRequest, CancellationToken.None);
Assert.True(response.Projects.Count == 1);
}
}
公共类GetProjectsTests
{
[事实]
公共异步任务GetProjectsTest()
{
var项目=新列表
{
新项目
{
Id=1,
Name=“测试”
}
};
var context=newmock();
Setup(c=>c.Projects).Returns(Projects.AsQueryable().BuildMockDbSet().Object);
var mapper=newmock();
mapper.Setup(x=>x.ConfigurationProvider)
.返回(
()=>新的MapperConfiguration(
cfg=>{cfg.CreateMap();}));
var getProjectsRequest=新建getProjectsRequest();
var handler=new GetProjectsHandler(context.Object,mapper.Object);