Reputation: 5459
I am currently working with Moq to do some unit testing. I am running into an issue where I am specifying what my mocked object returns, but the actual call is returning null instead of what I am specifying in .Returns(...)
. I've reviewed other posts and one of the suggestions was to create the mock with MockBehavior.Strict
- after doing this, I get a fairly verbose error as follows:
IMyRepository.Save(MvcIndividualAuth.Data.Models.DTO.MyTableDTO) invocation failed with mock behavior Strict. All invocations on the mock must have a corresponding setup.`
However, I am calling setup on the only method that my mocked object calls already. Please see code below:
My test:
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 method:
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;
}
Why is the mocked repo in my test not returning the value I specify in my Returns(..)
call? All help is appreciated.
Update: as requested, here is MyRepository.Save method and 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;
}
Upvotes: 3
Views: 3301
Reputation: 12171
You get null
because GetDto()
returns object different from myDto
- references are different.
You can change your Setup()
to return myDto
:
_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns(myDto);
Or if you want to return object which was passed as a parameter:
_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns((MyTableDTO dto) => dto);
Or if you want to mock based on some properties:
_myRepoMock.Setup(x => x.Save(It.Is<MyTableDTO>(dto => dto.Id == 1))).Returns(myDto);
Or if you want to modify return result:
_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns((MyTableDTO dto) => { dto.Id = 2; return dto;});
You can also combine all approaches.
Upvotes: 5
Reputation: 11841
The MyTableDTO
returned by GetDTO
is a new MyTableDTO
which is not the same as the rule in your Setup
, because it has a different reference, hence there is no matching setup for Save
.
Instead you can try something like:
_myRepo.Setup(s => s.Save(It.Is<MyTableDTO>(d => d.Equals(myDto))).Returns(myDto);
Or, if you are not concerned about the exact values passed to Save
:
_myRepo.Setup(s => s.Save(It.IsAny<MyTableDTO>()).Returns(myDto);
Upvotes: 3