【问题标题】:MOQ'd object returning null despite specifying .Returns尽管指定了 .Returns,但最小起订量对象返回 null
【发布时间】:2017-08-03 13:27:45
【问题描述】:

我目前正在与 Moq 合作进行一些单元测试。我遇到了一个问题,我正在指定我的模拟对象返回的内容,但实际调用返回 null 而不是我在 .Returns(...) 中指定的内容。我已经查看了其他帖子,其中一个建议是使用 MockBehavior.Strict 创建模拟 - 这样做之后,我得到一个相当详细的错误,如下所示:

IMyRepository.Save(MvcIndividualAuth.Data.Models.DTO.MyTableDTO) invocation failed with mock behavior Strict. All invocations on the mock must have a corresponding setup.

但是,我在我的模拟对象已经调用的唯一方法上调用 setup。请看下面的代码:

我的测试:

    MyService _myService;
    Mock<IMyRepository> _myRepoMock;

    [TestInitialize]
    public void Setup()
    {
      _myRepoMock = new Mock<IMyRepository>();
      _myService = new MyService(_myRepoMock.Object);
    }

[TestMethod]
    public void MyServiceSave()
    {
      //Arrange
      var myDto = new MyTableDTO { Id = 1, Bar = 5, Foo = "Test" };
      _myRepoMock.Setup(x => x.Save(myDto)).Returns(myDto);

      //Act
      var vm = _myService.Save(new MyTableViewModel(myDto));

      //Assert
      Assert.AreEqual(vm.Id, 1);
      Assert.AreEqual(vm.Foo, "Test");
      Assert.AreEqual(vm.Bar, 5);
      Assert.AreEqual(vm.BarPlusFoo, "5 Test");
    }

MyService.Save 方法:

    public MyTableViewModel Save(MyTableViewModel viewModel)
    {
      var dto = MyTableViewModel.GetDto(viewModel);
      var dbDto = _myRepo.Save(dto);    //_myRepo is of type IMyRepository, 
                                        // this _myRepo.Save call is returning null

      var vm = new MyTableViewModel(dbDto);

      return vm;
    }

为什么我的测试中的模拟存储库没有返回我在.Returns(..) 调用中指定的值?感谢所有帮助。

编辑:根据要求,这里是 MyRepository.Save 方法和 MyTableViewModel.GetDto():

MyRepository.Save:

public MyTableDTO Save(MyTableDTO dto)
    {
      try
      {
        var entity = new MyTable();

        if (String.IsNullOrEmpty(dto.Foo))
        {
          throw new ArgumentException("MyTable requires Foo");
        }

        if (dto.Id == 0)
        {
          //added
          entity.Update(dto);
          _db.MyTables.Add(entity);
        }
        else
        {
          //modified
          entity = _db.MyTables.Single(x => x.Id == dto.Id);

          entity.Update(dto);
        }

        _db.SaveChanges();

        return new MyTableDTO(entity);
      }
      catch (Exception)
      {
        throw;
      }
    }

MyTableViewModel.GetDto(..);

public static MyTableDTO GetDto(MyTableViewModel vm)
    {
      var dto =  new MyTableDTO
      {
        Bar = vm.Bar,
        Foo = vm.Foo,
        Id = vm.Id
      };

      return dto;
    }

【问题讨论】:

  • 你能显示Repository.Save()方法吗?
  • 请附上GetDto的源代码。
  • @RomaDoskoch 更新以显示请求
  • @mjwills 已更新以显示请求
  • 看来您用于设置的myDto 对象与测试中实际使用的对象与GetDto 创建的对象不同

标签: c# asp.net .net unit-testing moq


【解决方案1】:

您得到null,因为GetDto() 返回的对象不同于myDto - 引用不同。

您可以将您的Setup() 更改为返回myDto

_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns(myDto);

或者如果你想返回作为参数传递的对象:

_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns((MyTableDTO dto) => dto);

或者如果您想基于某些属性进行模拟:

_myRepoMock.Setup(x => x.Save(It.Is<MyTableDTO>(dto => dto.Id == 1))).Returns(myDto);

或者如果你想修改返回结果:

_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns((MyTableDTO dto) => { dto.Id = 2; return dto;});

您还可以组合所有方法。

【讨论】:

    【解决方案2】:

    GetDTO 返回的MyTableDTO 是一个新的MyTableDTO,它与Setup 中的规则不同,因为它具有不同的引用,因此Save 没有匹配设置。

    您可以尝试以下方法:

    _myRepo.Setup(s => s.Save(It.Is<MyTableDTO>(d => d.Equals(myDto))).Returns(myDto); 
    

    或者,如果您不关心传递给 Save 的确切值:

    _myRepo.Setup(s => s.Save(It.IsAny<MyTableDTO>()).Returns(myDto); 
    

    【讨论】:

      猜你喜欢
      • 2020-07-25
      • 2021-10-27
      • 2014-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多