3

I have a project created using Asp.Net Core, but I have a problem with unit testing one part of my controller's action, I use xUnit.net(2.2.0-beta2-build3300) for testing and Moq(4.6.25-alpha) for mocking, and FluentAssertions(4.13.0) and GenFu(1.1.1) to help me with my tests, I have a Unit of Work class (note that I cut it down to what's relevant to my question):

public class UnitOfWork : IUnitOfWork
{

    private readonly WebForDbContext _context;

    public UnitOfWork(WebForDbContext context)
    {
        _context = context;
    }

     private IContactRepository _contactRepository;

     public IContactRepository ContactRepository
    {
        get
        {

            if (this._contactRepository == null)
            {
                this._contactRepository = new ContactRepository(_context);
            }
            return _contactRepository;
        }
    }
}

In my ContactRepository I have:

public class ContactRepository:IContactRepository
{
    private WebForDbContext _context;

    public ContactRepository(WebForDbContext context)
    {
        _context = context;
    }

    public Task<int> AddNewContactAsync(Contact contact)
    {
        _context.Contacts.Add(contact);
        return _context.SaveChangesAsync();
    }
}

I inject the Unit of Work to my controller, my action:

 [HttpPost]
 [ValidateAntiForgeryToken]
 public async Task<IActionResult> Create(ContactViewModel contactViewModel)
  {
       var contactWioutJavascript = _webForMapper.ContactViewModelToContact(contactViewModel);

       int addContactResultWioutJavascript = await _uw.ContactRepository.AddNewContactAsync(contactWioutJavascript);

        if (addContactResultWioutJavascript > 0)
        {
            return View("Success");
        }
  }

What I want to do is to stub my AddNewContactAsync method to return an integer bigger than 0 (10 in this case), to inter the if clause, and test to see if the correct view is returned, my test class:

public class ContactControllerTests
{

 private Mock<IUnitOfWork> _uw;
 private Mock<IWebForMapper> _webForMapper;

    public ContactControllerTests()
    {
        _uw = new Mock<IUnitOfWork>();

        _webForMapper = new Mock<IWebForMapper>();
    }

   [Fact]
    public async Task Create_SouldReturnSuccessView_IfNewContactAdded()
    {
        var contactViewModel = A.New<ContactViewModel>();

        _webForMapper.Setup(s => s.ContactViewModelToContact(contactViewModel)).Returns(A.New<Contact>());

        _uw.Setup(u => u.ContactRepository.AddNewContactAsync(A.New<Contact>())).ReturnsAsync(10);

        var sut = new ContactController(_uw.Object, _webForMapper.Object);

        var result = (ViewResult)await sut.Create(contactViewModel);

        result.ViewName.Should().Be("Success");
    }
 }

But the method AddNewContactAsync returns 0, and my test doesn't enter the if condition that leads to return View("Success"), I know that the problem doesn't have to do with ReturnAsync because I've used it with other async methods and it works, also _webForMapper is stubbed correctly and map the view model to my domain model and contactWioutJavascript is populated with value, but when I debug the test and reach the addContactResultWioutJavascript line, it returns 0, no matter what I do.

The things I did, but didn't work:

I mocked the ContactRepository, and tried to stub that instead:

_contactRepository.Setup(c => c.AddNewContactAsync(A.New<Contact>())).ReturnsAsync(10);

_uw.SetupGet<IContactRepository>(u => u.ContactRepository).Returns(_contactRepository.Object);

I also found other questions:

Moq Unit of Work

how to moq simple add function that uses Unit of Work and Repository Pattern

Mocking UnitOfWork with Moq and EF 4.1

But none of them helped, I'd appreciate any help.

Community
  • 1
  • 1
Hamid Mosalla
  • 3,279
  • 2
  • 28
  • 51
  • 1
    On a side note on the terminology used, to avoid confusion: What you do there is not stubbing, its mocking (hence the name for this type of frameworks). Stubbing is a test implementation of the interface or base class, which usually means you need to implement all interface methods/properties where as in mock you can only configure/mock the one you need in your test – Tseng Aug 11 '16 at 19:24
  • @Tseng According to [this](http://stackoverflow.com/a/27151309/1650277), _Stub - override methods to return hard-coded values, also referred to as state-based_, and I think this is what I did with `AddNewContactAsync` method, but I still might be wrong. – Hamid Mosalla Aug 12 '16 at 04:03

1 Answers1

4

You are almost there. Two things:

  1. You do need to setup the ContactRepository property as Moq doesn't support "chaining" of setups.

  2. Also, you need to use It.IsAny<>() instead of A.New<>():

    _contactRepository.Setup(c => c.AddNewContactAsync(It.IsAny<Contact>())).ReturnsAsync(10);
    

    This says "match any Contact that is passed in". When you used A.New<>(), you were saying "match the Contact instance that I just created with A.New<>(). In effect, that will never match anything since you didn't save or use the return value of A.New<>().

Patrick Quirk
  • 23,334
  • 2
  • 57
  • 88