单元测试Url.Action(使用Rhino Mocks?)

Kri*_*Ahl 12 asp.net-mvc unit-testing rhino-mocks urlhelper

我正在尝试为UrlHelper扩展方法编写一个测试,如下所示:

Url.Action<TestController>(x => x.TestAction());
Run Code Online (Sandbox Code Playgroud)

但是,我似乎无法正确设置它,以便我可以创建一个新的UrlHelper,然后断言返回的url是预期的url.这就是我所拥有的,但我对任何不涉及嘲弄的事情持开放态度.; 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"));
    }
Run Code Online (Sandbox Code Playgroud)

我尝试将其更改为urlHelper.Action("Test","TestAction"),但无论如何都会失败,所以我知道这不是我的扩展方法无法正常工作.NUnit返回:

NUnit.Framework.AssertionException: Expected string length 15 but was 0. Strings differ at index 0.
Expected: "Test/TestAction"
But was:  <string.Empty>
Run Code Online (Sandbox Code Playgroud)

我已经验证路由已注册并正在工作,我正在使用Hanselmans扩展来创建虚假的HttpContext.这是我的UrlHelper extentionmethod的样子:

        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;
    }
Run Code Online (Sandbox Code Playgroud)

任何关于我缺少什么的想法让它工作???/Kristoffer

小智 11

它无法工作的原因是RouteCollection对象在内部调用HttpResponseBase上的ApplyAppPathModifier方法.看起来Hanselman的模拟代码没有对该方法设置任何期望,因此它返回null,这就是为什么你对UrlHelper上的Action方法的所有调用都返回一个空字符串.修复是在HttpResponseBase mock的ApplyAppPathModifier方法上设置一个期望,只返回传递给它的值.我不是Rhino Mocks专家,所以我不完全确定语法.如果您使用Moq,那么它将如下所示:

httpResponse.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>()))
    .Returns((string s) => s);
Run Code Online (Sandbox Code Playgroud)

或者,如果你只是使用手动模拟,这样的东西会起作用:

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码应该是HttpContextBase的最小必要实现,以便为UrlHelper进行单元测试传递.我尝试了它,它的工作原理.希望这可以帮助.