0

As the title says, I'm attempting to resolve an interface that implements a concrete class that also takes a constructor.

Here's the concrete service class as an example:

public class MessageService : IMessageService
{
    private readonly IMessageGenerator _messageGenerator;

    public MessageService(IMessageGenerator messageGenerator)
    {
        _messageGenerator = messageGenerator;
    }

    public string GetMessage()
    {
        return string.Concat(_messageGenerator.GetMessage(), "");
    }
}

As you can see this service class also requires an interface as a constructor parameter. The MVC controller constructor looks like this:

    private readonly IMessageService _messageSvc;

    public HomeController(IMessageService messageSvc)
    {
        _messageSvc = messageSvc;
    }

I have resolved the interfaces in a Bootstrapper thanks to Unity.Mvc3

var container = new UnityContainer();

container
        .RegisterType<IMessageService, MessageService>()
        .RegisterType<IMessageGenerator, MessageGenerator>();

So the main issue I'm having is how can I pass a mocked instance of the IMessageGenerator interface to the IMessageService inside a unit test using UnityAutoMoq? I would think that something like this would work, but it doesn't:

    [TestMethod]
    public void Index()
    {
        var container = new UnityAutoMoqContainer();
        var controllerContext = container.Resolve<ControllerContext>();
        var nMsgSvc = container.Resolve<IMessageService>(container.Resolve<IMessageGenerator>);
        var sut = new HomeController(nMsgSvc) { ControllerContext = controllerContext };

        ViewResult result = sut.Index() as ViewResult;

        Assert.AreEqual("Hello from the MessageGenerator via the MessageService", result.ViewBag.Message);
    }
Spock
  • 7,009
  • 1
  • 41
  • 60

2 Answers2

2

You don't need to do that when you are testing the controller. In that situation, the controller only needs a mock of the IMessageService.

Additionally, to test the Index method, I would not use the container at all, as it is not involved.

Something like this should do it:

// arrange
var messageService = new Mock<IMessageService>();
// setup message service
...

var controller = new HomeController(messageService.Object);

// act
...
Damian Schenkelman
  • 3,505
  • 1
  • 15
  • 19
1

This questions was asked long time ago. But I would provide an answer which might helpful. You really don't want to stub the IMessageGenerator. What you want is to stub out is the IMessageService. And configure it to return the message you want. What returns from IMessageGenerator does not not a concern for your Controller. It would only become a concern if you consume IMessageGenerator within the Controller.

Note that your test also not written well with the usage of UnityAutoMoq container.

You can configure the IMessageService to return a desired string as below.

    [TestMethod]
    public void Index_ViewData_ContainsExpectedMessage()
    {
        var container = new UnityAutoMoqContainer();
        var messageToReturnViaMessageGenerator = "Hello from the MessageGenerator via the MessageService";                        
        var messageGenratorStub = container.GetMock<IMessageService>();
        messageGenratorStub.Setup(x => x.GetMessage()).Returns(messageToReturnViaMessageGenerator);
        var sut = container.Resolve<HomeController>();

        ViewResult result = sut.Index() as ViewResult;

        Assert.AreEqual(messageToReturnViaMessageGenerator, result.ViewBag.Message);
    }

There are few things to note

  • You don't need to resolve the ControllerContext - It is unnecessary for the purpose of this test
  • Resolving Sut...

        var sut = container.Resolve<HomeController>();
    

This would return your sut (System Under Test). This instance can also contain any stubbed instances you have stubbed with the UnityAutoMoqContainer. In this case it is the stubbed IMessageService. This way you don't have to explicitly pass the stubbed IMessageService instance to the Controller's constructor.

  • Just a minor - always give a readable test name ;)

HTH

Spock
  • 7,009
  • 1
  • 41
  • 60