views:

130

answers:

2

When attempting to follow the article on mocking the htmlhelper with Moq I ran in to the following problem. The exception is thrown on creation of the htmlhelper. I am only guessing that castle windsor is being used (by seeing the error message).

The exception:

MissingMethodException occurred

Constructor on type 'Castle.Proxies.ViewContextProxy' not found.

Stack Trace:

at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)

The Code:

    public static HtmlHelper CreateHtmlHelper(ViewDataDictionary vd)
    {
        Mock<ViewContext> mockViewContext = new Mock<ViewContext>(
                                                new ControllerContext(
                                                    new Mock<HttpContextBase>().Object,
                                                    new RouteData(),
                                                    new Mock<ControllerBase>().Object),
                                                new Mock<IView>().Object,
                                                vd,
                                                new TempDataDictionary());

        Mock<IViewDataContainer> mockViewDataContainer = new Mock<IViewDataContainer>();
        mockViewDataContainer.Setup(v => v.ViewData).Returns(vd);

        return new HtmlHelper(mockViewContext.Object, mockViewDataContainer.Object);
    }

I am using ASP MVC 2, Moq 4.0 beta 3, VS2010, using the IDE's testing framework.

How do I resolve the issue and return an instance of HtmlHelper?

+4  A: 

You get MissingMethodException when MOQ can't match parameters to Mock<>() to the parameters on the mocked class's constructor.

Looking at ViewContext explains why. There is only one constructor overload and it is this:

 public ViewContext(ControllerContext controllerContext, IView view, ViewDataDictionary viewData, TempDataDictionary tempData, TextWriter writer);

This setup(includes missing TextWriter mock) should work:

   Mock<ViewContext> mockViewContext = new Mock<ViewContext>(
     new ControllerContext(
     new Mock<HttpContextBase>().Object,
     new RouteData(),
     new Mock<ControllerBase>().Object),
     new Mock<IView>().Object,
     vd,
     new TempDataDictionary()
     new Mock<TextWriter>().Object);

PS MOQ uses Castle Dynamic Proxy to create mocked classes at runtime, hence the name Castle in the exception that you are seeing. Castle Windsor uses Dynamic Proxy project, but they are quite distinct projects.

Igor Zevaka
MedicineMan
Havard S, the original author of the article was nice enough to answer my question, post an update to his blog and post the solution to SO as well. You were very very very close, and I wish I could award you the "answer" as well.
MedicineMan
Oh of course, I forgot to do .Object. No worries at all, I'll update the answer so it's correct for other people.
Igor Zevaka
+1  A: 

I've reproduced your issue with the code from my blog post. The following updated method works for me:

public static HtmlHelper CreateHtmlHelper(ViewDataDictionary vd)
{
    Mock<ViewContext> mockViewContext = new Mock<ViewContext>(
        new ControllerContext(
            new Mock<HttpContextBase>().Object,
            new RouteData(),
            new Mock<ControllerBase>().Object),
        new Mock<IView>().Object,
        vd,
        new TempDataDictionary(),
        new Mock<TextWriter>().Object);

    var mockViewDataContainer = new Mock<IViewDataContainer>();
    mockViewDataContainer.Setup(v => v.ViewData)
        .Returns(vd);

    return new HtmlHelper(mockViewContext.Object,
                            mockViewDataContainer.Object);
}

I have posted an update on my blog as well.

Håvard S
The key difference between this answer and the one supplied by Igor Zevaka is that the Mock<ViewContext> is created with Mock<TextWriter>().Object.
MedicineMan