JazzMaster
JazzMaster

Reputation: 717

Unit Testing with DbContext mock through Service Layer

I'm a beginner at writing unit tests and I have a test I'm trying to get working. I'll start of by explaining what I'm trying to test.

I'm trying to test a method which saves messages in a Mvc 4 project. The method is called SaveMessage and is shown below.

namespace ChatProj.Service_Layer
{
    public class UserService : IUserService
    {
        public MessageContext messageContext = new MessageContext();

        public UserService()
        {
            _messageRepository = new MessageRepository(messageContext);
        }

        private  IMessageRepository _messageRepository;

    ->  public void SaveMessage(Message message)
        {
             messageContext.Messages.Add(message);
            _messageRepository.Save();
        }

The _messageRepository.Save in the SaveMessage method is implemented in my DAL layer MessageRepository and looks like this:

public void Save()
        {
            context.SaveChanges();
        }

This way of saving will seem a bit overcomplicated, but I structured the project this way because I didn't want the service layer (IUserService & UserService) to handle operations that could & should (i think) be handled by the Data Access Layer (IMessageRepository & MessageRepository).

Now comes the tricky part. I've been trying to understand how I could unit test this. This is my try:

namespace ChatProj.Tests
{
    [TestFixture]
    class MessageRepositoryTests
    {
        [SetUp]
        public void Setup()
        {

        }

        [Test]
    public void SaveMessage_SaveWorking_VerifyUse()
    {
        //Arrange
        var userServiceMock = new Mock<UserService>();
        var message = new Message { MessageID = 0, Name = "Erland", MessageString = "Nunit Test", MessageDate = DateTime.Now };
        var repositoryMock = new Mock<IMessageRepository>();
        var contextMock = new Mock<MessageContext>();
        MessageRepository messageRepository = new MessageRepository(contextMock.Object);
        UserService userService = new UserService();

        //Act
        userService.SaveMessage(message);

        //Assert
        repositoryMock.Verify(m => m.Save());
        userServiceMock.Verify(m => m.SaveMessage(message));
    }
}

I get this error: Imgur link , and I'm not quite sure how to solve it. I've tried looking at several other SO posts but I fail to make the test work.

So I'm wondering, how do I practically get my Unit Test to work?

Upvotes: 0

Views: 2997

Answers (2)

matt
matt

Reputation: 9401

Take a look at these two lines:

UserService userService = new UserService();

//Act
userService.SaveMessage(message);

You're creating a userService instance, and then immediately saving your message. Now jump into the SaveMessage code.

public void SaveMessage(Message message)
{
     messageContext.Messages.Add(message);
    _messageRepository.Save();
}

Ok, now you're adding stuff to messageContext, and then calling _messageRepository.Save(). But where are messageContext and _messageRepository instantiated?

public MessageContext messageContext = new MessageContext();

public UserService()
{
    _messageRepository = new MessageRepository(messageContext);
}

You're creating them at instantiation. The mocks that you've created in your test aren't being used. Instead of creating instances of these objects in the constructor, you might consider passing them into the UserService constructor as arguments. Then, you can pass in mocked instances in your test.

Upvotes: 1

Oleksandr Kobylianskyi
Oleksandr Kobylianskyi

Reputation: 3380

You should setup your MessageContext properties to return fake data and don't make real Db call with SaveChanges method. Right now it still tries to access a real DB.

But you can setup only virtual properties or if it will be an inteface.

So the best solution is to extract an interface from your MessageContext and inject it into repository. Then you can easily mock your IMessageContext interface and force it to return appropriate in-memory data.

Upvotes: 2

Related Questions