Shawn Mclean
Shawn Mclean

Reputation: 57469

Using Moq to mock a repository that returns a value

How do I set up my test method on that mocks a repository which accepts an object?

This is what I have so far:

Service.cs

    public int AddCountry(string countryName)
    {
        Country country = new Country();
        country.CountryName = countryName;
        return geographicsRepository.SaveCountry(country).CountryId;
    }

test.cs

    [Test]
    public void Insert_Country()
    {
        //Setup
        var geographicsRepository = new Mock<IGeographicRepository>();

        geographicsRepository.Setup(x => x.SaveCountry(It.Is<Country>(c => c.CountryName == "Jamaica"))); //How do I return a 1 here?

        GeographicService geoService = new GeographicService(geographicsRepository.Object);

        int id = geoService.AddCountry("Jamaica");

        Assert.AreEqual(1, id);
    }

SaveCountry(Country country); returns an int.

I need to do 2 things:

  1. First test, I need to tell the setup to return an int of 1.
  2. I need to create a second test Insert_Duplicate_Country_Throws_Exception(). In my Setup, how do I tell the repository to throw an error when I do:

    int id = geoService.AddCountry("Jamaica");
    int id = geoService.AddCountry("Jamaica");
    

Framework:

  1. NUnit.
  2. Moq.
  3. ASP.NET MVC - repository pattern.

Upvotes: 8

Views: 15477

Answers (2)

Tim Lloyd
Tim Lloyd

Reputation: 38474

I think maybe you are slightly misunderstanding the purpose of testing with mocks in the two scenarios you have supplied.

In the first scenario, you wish to test that 1 is returned when you pass in "Jamaica". This is not a mock test case but a test case for real behaviour as you wish to test a specific input against an expected output i.e. "Jamaica" -> 1. In this situation mocking is more useful to ensure that internally your service calls SaveCountry on the repository with the expected country, and that it returns the value from the call.

Setting up your "SaveCountry" case and then calling "VerifyAll" on your mock is the key. This will assert that "SaveCountry" was indeed called with country "Jamaica", and that the expected value is returned. In this way you have confidence that your service is wired up to your repository as expected.

[Test]
public void adding_country_saves_country()
{
    const int ExpectedCountryId = 666;

    var mockRepository = new Mock<IGeographicRepository>();

    mockRepository.
      Setup(x => x.SaveCountry(It.Is<Country>(c => c.CountryName == "Jamaica"))).
      Returns(ExpectedCountryId); 

    GeographicService service= new GeographicService(mockRepository.Object);

    int id = service.AddCountry(new Country("Jamaica"));

    mockRepo.VerifyAll();

    Assert.AreEqual(ExpectedCountryId, id, "Expected country id.");
}

In the second scenario you wish to test that an exception is raised when you attempt to add a duplicate country. There's not much point in doing this with a mock as all you will test is that your mock has behaviour when adding duplicates, not your real implementation.

Upvotes: 1

Tyler Treat
Tyler Treat

Reputation: 15008

Your first test should look something like this:

[Test]
public void Insert_Country()
{
    Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
    GeographicService geoService = new GeographicService(geographicsRepository.Object);

    // Setup Mock
    geographicsRepository
        .Setup(x => x.SaveCountry(It.IsAny<Country>()))
        .Returns(1);

    var id = geoService.AddCountry("Jamaica");

    Assert.IsInstanceOf<Int32>(id);
    Assert.AreEqual(1, id);
    geographicsRepository.VerifyAll();
}

The second test should look like this:

[Test]
public void Insert_Duplicate_Country_Throws_Exception()
{
    Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
    GeographicService geoService = new GeographicService(geographicsRepository.Object);

    // Setup Mock
    geographicsRepository
        .Setup(x => x.SaveCountry(It.IsAny<Country>()))
        .Throws(new MyException());

    try
    {
        var id = geoService.AddCountry("Jamaica");
        Assert.Fail("Exception not thrown");
    }
    catch (MyException)
    {
        geographicsRepository.VerifyAll();
    }
}

Upvotes: 8

Related Questions