微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

自动映射器的 xUnit 和 .Net 核心后测试用例问题我猜

如何解决自动映射器的 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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?