Umut Esen Umut Esen - 13 days ago 5
C# Question

Unit Test MVC 5 Controller Create Action with Unit of Work and Repository

I am trying to test a controller action that accepts a view model and creates a new entry. Here is the controller action:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ContactViewModel viewModel)
{
if (!ModelState.IsValid)
return View("Create", viewModel);

_unitOfWork.Contacts.Add(Mapper.Map(viewModel, new Contact()));

_unitOfWork.Complete();

return RedirectToAction("Index");
}


And the unit test:

[TestClass]
public class ContactControllerTests
{
private ContactsController _controller;
private Mock<IContactRepository> _mockRepository;
private string _userId;
private Mock<IUnitOfWork> _mockUoW;

[ClassInitialize]
public static void Init(TestContext context)
{
Mapper.Initialize(c => c.AddProfile<MappingProfile>());
}

[TestInitialize]
public void TestInitialize()
{
_userId = "1";
_mockRepository = new Mock<IContactRepository>();
_mockUoW = new Mock<IUnitOfWork>();

_mockUoW.SetupGet(u => u.Contacts).Returns(_mockRepository.Object);

_controller = new ContactsController(_mockUoW.Object);

_controller.MockCurrentUser(_userId, "user@domain.com");
}

[TestMethod]
public void CreatePost_ValidValuesSubmitted_ShouldCallComplete()
{
var viewModel = new ContactViewModel()
{
FirstName = "a",
LastName = "b"
};

_controller.Create(viewModel);

_mockRepository.Object.GetContacts(_userId).Should().HaveCount(1);
}
}


The unit test always returns the count 0 while I expect it to be 1. I am pretty new to TDD and I implemented unit of work and repository pattern as shown in Mosh Hamedani's course at:
https://app.pluralsight.com/library/courses/full-stack-dot-net-developer-architecture-testing/table-of-contents

Answer

You have not mocked any behavior for the repository in the above example.

Based on provided example, let's assume a simple interface like this.

public interface IContactRepository {
    void Add(Contact contact);
    IEnumerable<Contact> GetContacts(string _userId);
}

You need to have some form of storage for your data.

[TestInitialize]
public void TestInitialize() {
    _userId = "1";
    var data = new List<Contact>();//To store test data.
    //Configure repository
    _mockRepository = new Mock<IContactRepository>();
    _mockRepository.Setup(m => m.Add(It.IsAny<Contact>())).Callback<Contact>(data.Add);
    _mockRepository.Setup(m => m.GetContacts(_userId)).Returns(data);
    //Configure UoW
    _mockUoW = new Mock<IUnitOfWork>();
    _mockUoW.SetupGet(u => u.Contacts).Returns(_mockRepository.Object);

    _controller = new ContactsController(_mockUoW.Object);

    _controller.MockCurrentUser(_userId, "user@domain.com");
}

or forego the mock and create a fake.

public class FakeContactRepository : IContactRepository {
    private ICollection<Contact> data;

    public FakeContactRepository(ICollection<Contact> data) {                
        this.data = data;
    }

    public void Add(Contact contact) {
        data.Add(contact);
    }

    public IEnumerable<Contact> GetContacts(string _userId) {
        return data;
    }
}

and set it up for the test.

[TestInitialize]
public void TestInitialize() {
    _userId = "1";
    var data = new List<Contact>();//To store test data.
    //Configure repository
    var fakeRepository = new FakeContactRepository(data);
    //Configure UoW
    _mockUoW = new Mock<IUnitOfWork>();
    _mockUoW.SetupGet(u => u.Contacts).Returns(fakeRepository );

    _controller = new ContactsController(_mockUoW.Object);

    _controller.MockCurrentUser(_userId, "user@domain.com");
}
Comments