Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unittesting Url.Action (using Rhino Mocks?)

I'm trying to write a test for an UrlHelper extensionmethod that is used like this:

Url.Action<TestController>(x => x.TestAction());

However, I can't seem set it up correctly so that I can create a new UrlHelper and then assert that the returned url was the expected one. This is what I've got but I'm open to anything that does not involve mocking as well. ;O)

        [Test]
    public void Should_return_Test_slash_TestAction()
    {
        // Arrange
        RouteTable.Routes.Add("TestRoute", new Route("{controller}/{action}", new MvcRouteHandler()));
        var mocks = new MockRepository();
        var context = mocks.FakeHttpContext(); // the extension from hanselman
        var helper = new UrlHelper(new RequestContext(context, new RouteData()), RouteTable.Routes);

        // Act
        var result = helper.Action<TestController>(x => x.TestAction());

        // Assert
        Assert.That(result, Is.EqualTo("Test/TestAction"));
    }

I tried changing it to urlHelper.Action("Test", "TestAction") but it will fail anyway so I know it is not my extensionmethod that is not working. NUnit returns:

NUnit.Framework.AssertionException: Expected string length 15 but was 0. Strings differ at index 0.
Expected: "Test/TestAction"
But was:  <string.Empty>

I have verified that the route is registered and working and I am using Hanselmans extension for creating a fake HttpContext. Here's what my UrlHelper extentionmethod look like:

        public static string Action<TController>(this UrlHelper urlHelper, Expression<Func<TController, object>> actionExpression) where TController : Controller
    {
        var controllerName = typeof(TController).GetControllerName();
        var actionName = actionExpression.GetActionName();

        return urlHelper.Action(actionName, controllerName);
    }

    public static string GetControllerName(this Type controllerType)
    {
        return controllerType.Name.Replace("Controller", string.Empty);
    }

    public static string GetActionName(this LambdaExpression actionExpression)
    {
        return ((MethodCallExpression)actionExpression.Body).Method.Name;
    }

Any ideas on what I am missing to get it working??? / Kristoffer

like image 844
Kristoffer Ahl Avatar asked Jun 04 '09 15:06

Kristoffer Ahl


1 Answers

The reason it isn't working is that internally the RouteCollection object calls the ApplyAppPathModifier method on HttpResponseBase. It looks like Hanselman's mock code does not set any expectations on that method so it returns null, which is why all of your calls to the Action method on UrlHelper are returning an empty string. The fix would be to setup an expectation on the ApplyAppPathModifier method of the HttpResponseBase mock to just return the value that is passed into it. I'm not a Rhino Mocks expert so I'm not completely sure on the syntax. If you are using Moq, then it would look like this:

httpResponse.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>()))
    .Returns((string s) => s);

Or, if you just use a hand-rolled mock, something like this would work:

internal class FakeHttpContext : HttpContextBase
{
    private HttpRequestBase _request;
    private HttpResponseBase _response;

    public FakeHttpContext()
    {
        _request = new FakeHttpRequest();
        _response = new FakeHttpResponse();
    }

    public override HttpRequestBase Request
    {
        get { return _request; }
    }

    public override HttpResponseBase Response
    {
        get { return _response; }
    }
}

internal class FakeHttpResponse : HttpResponseBase
{
    public override string ApplyAppPathModifier(string virtualPath)
    {
        return virtualPath;
    }
}

internal class FakeHttpRequest : HttpRequestBase
{
    private NameValueCollection _serverVariables = new NameValueCollection();

    public override string ApplicationPath
    {
        get { return "/"; }
    }

    public override NameValueCollection ServerVariables
    {
        get { return _serverVariables; }
    }
}

The above code should be the minimum necessary implementation of HttpContextBase in order to make a unit test pass for the UrlHelper. I tried it out and it worked. Hope this helps.

like image 116
Andy Avatar answered Oct 12 '22 22:10

Andy