Martin Dawson
Martin Dawson

Reputation: 7657

Moq testing Delete method

I am trying to test my delete method for my service, to do this I am trying to add an item to the repository first. However, I don't think my mock repository add method is being called because _mockRepository.Object.GetAll() is always null. I have tried stepping in with the debugger and it just skips over it too. What am I doing wrong?

public class CommentServiceTest
{
    private Mock<IRepository<Comment>> _mockRepository;
    private ICommentService _service;
    private ModelStateDictionary _modelState;

    public CommentServiceTest()
    {
        _modelState = new ModelStateDictionary();
        _mockRepository = new Mock<IRepository<Comment>>();
        _service = new CommentService(new ModelStateWrapper(_modelState), _mockRepository.Object);
    }

    [Fact]
    public void Delete()
    {
        var comment = new Comment("BodyText")
        {
            Audio = new Audio(),
            Date = DateTime.Now
        };

        _mockRepository.Object.Add(comment);
        //Nothing in repository collection here still
        var commentToDelete = _mockRepository.Object.GetAll().First();
        _service.Delete(commentToDelete);

        Assert.DoesNotContain(commentToDelete, _mockRepository.Object.GetAll());
    }
}

public class Repository<T, TC> : IRepository<T> where T : class where TC : DbContext
{
    private bool _disposed;

    protected TC Context { get; }

    public Repository()
    {

    }

    public Repository(TC context)
    {
        Context = context;
    }

    public virtual IQueryable<T> GetAll()
    {
        return Context.Set<T>();
    }

    public virtual void Add(T entity)
    {
        Context.Set<T>().Add(entity);
        Save();
    }

    public virtual void Save()
    {
        Context.SaveChanges();
    }   
}

}

Upvotes: 1

Views: 10829

Answers (2)

poke
poke

Reputation: 388383

Your repository is a mock, so it does not contain any actual behavior by default. You first have to set up the mock to accept method calls on the mocked object. So in your case, you would first have to tell the mock to handle adds in some way (in addition to the deletes).

However, since you actually just want to test the service that deletes something from the service, you don’t need to add an object to the mock repository first. You actually just need to check whether the item is properly deleted from the mock repository. I.e. since the repository is a mock, you don’t need to really add something in order to delete it.

Your test should look like this:

[Fact]
public void Delete()
{
    // arrange
    var comment = new Comment("BodyText")
    {
        Audio = new Audio(),
        Date = DateTime.Now
    };

    // set up the repository’s Delete call
    _mockRepository.Setup(r => r.Delete(It.IsAny<Comment>()));

    // act
    _service.Delete(comment);

    // assert
    // verify that the Delete method we set up above was called
    // with the comment as the first argument
    _mockRepository.Verify(r => r.Delete(comment));
}

Also, I don’t know why the service handles the model state (and not the repository), but you should probably add an additional assert that the state was properly updated for the object too.

Upvotes: 10

DaveShaw
DaveShaw

Reputation: 52818

You are mocking out all of the methods on the IRepository<T> interface, but are not telling the mocked version what to do when Add or GetAll are called.

You need something like this:

_mockRepository
.Setup(r => r.Add(It.IsAny<Comment>()))
.Callback(c => _service.Add(c));

_mockRepository
.Setup(r => r.GetAll())
.Returns(_service.GetAll());

This (or something similar) will means Add puts things into your list, and GetAll returns what is in your list.

Alternatively, you could try adding the Comment into the service directly instead of into the repository. Without seeing how service is implemented, I can only guess though how this would work.

Upvotes: 3

Related Questions