I've got a method in SomeRepository that is like follows:
public async Task<Guid> InsertAsync(TEntity entity)
{
await _context.Set<TEntity>().AddAsync(entity);
await _context.SaveChangesAsync();
return entity.Id;
}
_context variable here is just an instance of a concrete implementation of EntityFrameworkCore DbContext.
Now there are some methods that I'd like to test and that use this method in a following manner:
public async SomeDto SomeMethod(){
var guid = await someRepository.InsertAsync(entity);
//...
//A bit of code that now relies on entire entity object and it's Id, which gets assigned same value as guid variable - this is a consequence of a side effect of InsertAsync, illustrated with this line
var someDto = new SomeDto(entity);
return someDto;
}
As I'm using Moq, I can mock this when testing like follows:
// setup
var guid = Guid.NewGuid();
someRepositoryMock.Setup(s => s.InsertAsync(It.IsAny<Data.Entities.SomeEntity>()))
.Returns<Data.Entities.SomeEntity>((a) =>
{
a.Id = guid;
return Task.Run(() => a.Id); }
);
var someClass = new SomeClass(someRepositoryMock.Object)
//act - this is a method I'd like to unit test
var result = await someClass.SomeMethod();
//assert - here
Assert.Equal(guid, result.Id);
//other asserts on result values here
Now, given this code as an example, the question is when you have a method you'd like to unit test, and it is reliant on a side effect of it's owner's dependency, is it really a good idea to recreate the side effect of a dependency in it's mock?
My justification for doing this is that by mocking this dependency along with all it's methods' side effects, I'm effectively isolating all aspects of this dependency that is of significance to the method I'm testing.
However, I have a hunch that something is not right here. It feels as if the same functionality - the mentioned side effect is just rewritten in the mock. The recreation of a side effect is of course very simple in this example, but a scenario is easily imagined where it can be arbitrarily complex and much tougher to recreate.
Ideally, all functions would be pure, and this problem would be gone. But this is not the case.