如何解决自动映射器的 xUnit 和 .Net 核心后测试用例问题我猜
我正在使用配置 .Net 5、Automapper、xUnit 等处理 CRUD 单元测试用例。
问题:
- 所以现在我在通话后和使用 Dto 时遇到了特别的问题。
- 我尝试了很多方法来解决它,如果我在 post call 中不使用 Dto 作为输入参数并且只使用 Entity 它自己,我也能够解决它。 (但我不想公开实体,所以我只想让它与 Dto 一起使用)
- 下面是不工作的测试,它是控制器端的实现。
失败的测试用例:
[Fact]
public void Posttest()
{
try
{
//Arrange
var surveyRequest = new SurveyRequest()
{
Id = 0,Name = "Survey Request 1",CreateDate = DateTime.Now,CreatedBy = 1
};
var addedSurveyRequest = new SurveyRequest()
{
Id = 1,CreatedBy = 1
};
//setup mock
Mock<IRepositoryWrapper> mockRepo = new Mock<IRepositoryWrapper>();
mockRepo.Setup(m => m.SurveyRequest.Add(addedSurveyRequest)).Returns(new Response<SurveyRequest>(true,addedSurveyRequest));
//auto mapper
var mockMapper = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new AutoMapperProfile());
});
var mapper = mockMapper.CreateMapper();
SurveyRequestController controller = new SurveyRequestController(repositories: mockRepo.Object,mapper: mapper);
//Act
var model = mapper.Map<SurveyRequest,SurveyRequestDto>(source: addedSurveyRequest);
var result = controller.Post(model); // The issue with this post call here is that response remains null on repository level.
//Assert
var okResult = result as OkObjectResult;
Assert.NotNull(okResult);
//we will make sure that returned object is dto and not actual entity
var response = okResult.Value as SurveyRequestDtoWithId;
Assert.NotNull(response);
Assert.Equal(expected: response.Name,actual: model.Name);
}
catch (Exception ex)
{
//Assert
Assert.False(true,ex.Message);
}
}
控制器端调用:
[HttpPost("Insert")]
public IActionResult Post([FromBody] SurveyRequestDto model)
{
try
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
//If I remove this mapping from here,test case will work. (see next working test case)
var entity = _mapper.Map<SurveyRequestDto,SurveyRequest>(source: model);
entity.CreateDate = System.DateTime.Now;
entity.CreatedBy = 1;
var response = _repositories.SurveyRequest.Add(entity: entity); //Response remains null here
_repositories.Save();
if (response.IsSuccess == true)
return new OkObjectResult(_mapper.Map<SurveyRequest,SurveyRequestDtoWithId>(source: response.Data));
else
return new ObjectResult(response.ErrorMessage) { StatusCode = 500 };
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
工作测试用例:
public void PostTest2()
{
try
{
//Arrange
var surveyRequest = new SurveyRequest()
{
Id = 0,CreatedBy = 1
};
//setup mock
Mock<IRepositoryWrapper> mockRepo = new Mock<IRepositoryWrapper>();
mockRepo.Setup(m => m.SurveyRequest.Add(surveyRequest)).Returns(value: new Response<SurveyRequest>(true,addedSurveyRequest));
//auto mapper
var mockMapper = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new AutoMapperProfile());
});
var mapper = mockMapper.CreateMapper();
//setup controlller
SurveyRequestController controller = new SurveyRequestController(repositories: mockRepo.Object,mapper: mapper);
//Act
//var model = mapper.Map<SurveyRequest,SurveyRequestDto>(source: surveyRequest);
var result = controller.Post2(entity: surveyRequest);
//Assert
var okResult = result as OkObjectResult;
Assert.NotNull(okResult);
///we will make sure that returned object is dto and not actual entity
var response = okResult.Value as SurveyRequestDtoWithId;
Assert.NotNull(response);
Assert.Equal(expected: response.Id,actual: addedSurveyRequest.Id);
Assert.Equal(expected: response.Name,actual: addedSurveyRequest.Name);
}
catch (Exception ex)
{
//Assert
Assert.False(true,ex.Message);
}
}
控制器端发布工作测试用例:
public IActionResult Post2([FromBody] SurveyRequest entity)
{
try
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
//var entity = _mapper.Map<SurveyRequestDto,SurveyRequest>(source: model);
//entity.CreateDate = System.DateTime.Now;
//entity.CreatedBy = 1;
var response = _repositories.SurveyRequest.Add(entity: entity); //This returns proper response with saved data and ID
_repositories.Save();
if (response.IsSuccess == true)
return new OkObjectResult(_mapper.Map<SurveyRequest,SurveyRequestDtoWithId>(source: response.Data));
else
return new ObjectResult(response.ErrorMessage) { StatusCode = 500 };
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
我不确定我的映射器测试用例设置是错误还是其他任何问题。我也尝试了很多方法,但到目前为止没有运气。因此,如果有人可以查看并提供帮助,请在此处发布,将不胜感激。
解决方法
如果您使用的是 IMapper
,那么您可以执行以下操作:
var mapperMock = new Mock<IMapper>();
mapperMock
.Setup(mapper => mapper.Map<SurveyRequestDto,SurveyRequest>(It.IsAny< SurveyRequestDto>()))
.Returns(surveyRequest);
此解决方案不使用 AutoMapperProfile
,但因为您只有一个映射,所以我认为这不是真正的问题。
如果您想在 Verify
上调用 mapperMock
,那么我建议像这样提取 Map
选择器委托:
private static Expression<Func<IMapper,SurveyRequestDto>> MapServiceModelFromRequestModelIsAny =>
mapper => mapper.Map<SurveyRequestDto,SurveyRequest>(It.IsAny< SurveyRequestDto>());
用法
//Arrange
mapperMock
.Setup(MapServiceModelFromRequestModelIsAny)
.Returns(surveyRequest);
...
//Assert
mapperMock
.Verify(MapServiceModelFromRequestModelIsAny,Times.Once);
更新 #1
在断言时尽可能明确也可能是有意义的。如果您愿意,您可以进行深度相等检查以确保在 Map
调用之前未修改控制器的参数:
private static Expression<Func<IMapper,SurveyRequestDto>> MapServiceModelFromRequestModel(SurveyRequestDto input) =>
mapper => mapper.Map<SurveyRequestDto,SurveyRequest>(It.Is< SurveyRequestDto>(dto => dto.deepEquals(input)));
//Assert
mapperMock
.Verify(MapServiceModelFromRequestModel(model),Times.Once);
这假设 deepEquals
可用作扩展方法。
更新 #2
事实证明,模拟存储库的 Setup
代码也有一些问题。也就是说,它使用了 surveyRequest
而不是 It.IsAny<SurveyRequest>()
。
因为 surveyRequest
被指定为预期参数,这就是为什么设置的代码路径从未被调用而是返回 null
。
将其更改为 It.IsAny
后,整个测试开始工作 :D
repoMock
.Setup(repo => repo.SurveyRequest.Add(It.IsAny<SurveyRequest>()))
.Returns(new Response<SurveyRequest>(true,addedSurveyRequest))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。