ASP.NET MVC - Testing issues Q and A

Edit on GitHub

WTF? When playing around with the ASP.NET MVC framework and automated tests using Rhino Mocks, you will probably find yourself close to throwing your computer trough the nearest window. Here are some common issues and answers:

Q: How to mock Request.Form?

A: When testing a controller action which expects Request.Form to be a NameValueCollection, a NullReferenceException is thrown... This is due to the fact that Request.Form is null.

Use Scott's helper classes for Rhino Mocks and add the following extension method:

[code:c#]

public static void SetupFormParameters(this HttpRequestBase request)
{
    SetupResult.For(request.Form).Return(new NameValueCollection());
}

[/code]

Q: I can't use ASP.NET Membership in my controller, every test seems to go bad...

A: To test a controller using ASP.NET Membership, you should use a little trick. First of all, add a new property to your controller class:

[code:c#]

private MembershipProvider membershipProvider;

public MembershipProvider MembershipProviderInstance {
    get {
        if (membershipProvider == null)
        {
            membershipProvider = Membership.Provider;
        }
        return membershipProvider;
    }
    set { membershipProvider = value; }
}

[/code]

By doing this, you will enable the use of a mocked membership provider. Make sure you use this property in your controller instead of the standard Membership class (i.e. MembershipProviderInstance.ValidateUser(userName, password) instead of Membership.ValidateUser(userName, password)).

Let's say you are testing a LoginController which should set an error message in the ViewData instance when authentication fails. You do this by creating a mocked MembershipProvider which is assigned to the controller. This mock object will be instructed to always shout "false" on the ValidateUser method of the MembershipProvider. Here's how:

[code:c#]

LoginController controller = new LoginController();
var fakeViewEngine = new FakeViewEngine();
controller.ViewEngine = fakeViewEngine;

MockRepository mocks = new MockRepository();
using (mocks.Record())
{
    mocks.SetFakeControllerContext(controller);
    controller.HttpContext.Request.SetupFormParameters();

    System.Web.Security.MembershipProvider membershipProvider = mocks.DynamicMock<System.Web.Security.MembershipProvider>();
    SetupResult.For(membershipProvider.ValidateUser("", "")).IgnoreArguments().Return(false);

    controller.MembershipProviderInstance = membershipProvider;
}
using (mocks.Playback())
{
    controller.HttpContext.Request.Form.Add("Username", "");
    controller.HttpContext.Request.Form.Add("Password", "");

    controller.Authenticate();

    Assert.AreEqual("Index", fakeViewEngine.ViewContext.ViewName);
    Assert.IsNotNull(
        ((IDictionary<string, object>)fakeViewEngine.ViewContext.ViewData)["ErrorMessage"]
    );
}

[/code]

More questions? Feel free to ask! I'd be happy to answer them.

kick it on DotNetKicks.com

This is an imported post. It was imported from my old blog using an automated tool and may contain formatting errors and/or broken images.

Leave a Comment

avatar

2 responses

  1. Avatar for Makka
    Makka March 20th, 2008

    Intresting post.
    You can use a smart syntax for MembershipProviderInstance getter :)

    get { return membershipProvider ?? Membership.Provider; }

  2. Avatar for maartenba
    maartenba March 20th, 2008

    True :-) Still too used to the "old" syntax...