尽管指定了.Returns,MOQ对象仍返回null

时间:2017-08-03 13:27:46

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

我目前正在与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;
    }

2 个答案:

答案 0 :(得分:3)

您得到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;});

您还可以合并所有方法。

答案 1 :(得分:2)

MyTableDTO返回的GetDTO是新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); 的确切值:

public static void main(String[] args) {

    JSONParser parser = new JSONParser();

    try {
        Object obj = parser.parse(new FileReader("src/bikes.json"));

        JSONObject jsonObject = (JSONObject) obj;
        //System.out.println(jsonObject);

        JSONArray bikeList = (JSONArray) jsonObject.get("BikeList");

        Iterator<String> iterator = bikeList.iterator();
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ParseException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }