简体   繁体   中英

Mocking a method in the same interface with MOQ

I have a method in a service which I want to test. That method calls another method in the same class. This method is already tested so I want to mock that method.

This is my setup:

private readonly Mock<INewsLetterRepository> _mockNewsLetterRepository;
private readonly Mock<INewsLetterService> _mockNewsLetterService;
private readonly INewsLetterService _newsLetterService;

public NewsLetterServiceTest()
{
    _mockNewsLetterRepository = new Mock<INewsLetterRepository>();
    _mockNewsLetterService = new Mock<INewsLetterService> {CallBase = true};
    _newsLetterService = new NewsLetterService(_mockNewsLetterRepository.Object);
}

And this is the test I am using:

[TestMethod]
public void CreateNewsLetter_Should_Return_Empty_NewsLetter()
{
    var template = new Template
                   {
                       PlaceHolders = new List<TemplatePlaceholder>()
                   };
    var newsLetter = new NewsLetter {Template = template};
    const string content = "<html><body><!--BROWSER--></body></html>";
    _mockNewsLetterService.Setup(x => x.BuildNewsLetterHTML(It.IsAny<NewsLetter>())).Returns(content);

    var actual = _mockNewsLetterService.Object.CreateNewsLetter(newsLetter);
    Assert.AreEqual(content, actual);
}

Now the problem is that the function I am mocking: BuildNewsLetterHTML returns null instead of the content it supposed to return.

Here is a simplified version of the function I want to test:

public string CreateNewsLetter(NewsLetter newsLetter)
{
    var newsletterHTML = BuildNewsLetterHTML(newsLetter);
    return newsletterHTML;
}

So the problem is that, at least as I see it, is that the function I mock doesn't return the content string it supposed to return. The test fails on Assert.AreEqual because the actual is null. Any of you have any idea why actual is null?

Thanks in advance.

It seems the problem is you are calling Mock<T>'s CreateNewsLetter method which has not been set up, and which also seems to be your method under test. You are not supposed test against your fakes, they are supposed to substitute out production code to assist in testing other code.

I suggest you use the extract and override pattern in this case, since you are wanting to cause fake implementation in a method of the same class that has a method under test.

Moq is great in some cases but I don't think there is anything wrong with using a small readable stub when the situation calls for it.

public class YourTestClass
{
    [TestMethod]
    public void CreateNewsLetter_Should_Return_Empty_NewsLetter()
    {
        var template = new Template
        {
            PlaceHolders = new List<TemplatePlaceholder>()
        };
        var newsLetter = new NewsLetter { Template = template };

        const string content = "<html><body><!--BROWSER--></body></html>";

        INewsletterService service = new BuildNewsLetterStub(content);
        string actual = service.CreateNewsLetter(newsLetter);

        Assert.AreEqual(content, actual);
    }
}


public class BuildNewsLetterStub : NewsLetterService
{
    private string _letter;

    public BuildNewsLetterStub(string letter)
    {
        _letter = letter;
    }
    public override string BuildNewsLetterHTML(NewsLetter newsLetter)
    {
        return _letter;
    }
}

To override BuildNewsLetterHTML it must be marked virtual.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM