ASP.NET MVC控制器单元测试

尝试在ASP.NET MVC 3 Web应用程序中执行一些控制器单元测试。

我的测试是这样的:

[TestMethod]
public void Ensure_CreateReviewHttpPostAction_RedirectsAppropriately()
{
   // Arrange.
   var newReview = CreateMockReview();

   // Act.
   var result = _controller.Create(newReview) as RedirectResult;

   // Assert.
   Assert.IsNotNull(result, "RedirectResult was not returned");
}

很简单。 基本上测试一个[HttpPost]动作以确保它返回一个RedirectResult (PRG模式)。 我没有使用RedirectToRouteResult因为没有重载支持锚链接。 继续。

现在,我使用Moq来模拟Http上下文,包括服务器变量,控制器上下文,会话等等。一切进展顺利。

直到我在我的操作方法中找到了这一行:

return Redirect(Url.LandingPageWithAnchor(someObject.Uri, review.Uri);

LandingPageWithAnchor是一个自定义HTML帮助程序:

public static string LandingPageWithAnchor(this UrlHelper helper, string uri1, string uri2)
{
   const string urlFormat = "{0}#{1}";

   return string.Format(urlFormat,
                helper.RouteUrl("Landing_Page", new { uri = uri1}),
                uri2);
}

基本上,我重定向到另一个页面,该页面是新内容的“着陆页”,并以新评论为主角。 凉。

现在,这个方法之前失败了,因为UrlHelper为null。

所以我在嘲笑中这样做了:

controller.Url = new UrlHelper(fakeRequestContext);

它进一步得到了它,但现在它失败了,因为路由表不包含“Landing_Page”的定义。

所以我知道我需要嘲笑“某事”,但我不知道它是否是:

a)路线表
b)UrlHelper.RouteUrl方法
c)我写的UrlHelper.LandingPageWithAnchor扩展方法

任何人可以提供一些指导?

编辑

这个特定的路线是在一个区域 ,所以我尝试在我的单元测试中调用区域注册:

AreaRegistration.RegisterAllAreas();

但我得到一个InvalidOperationException

在应用程序的预启动初始化阶段不能调用此方法。


通过模拟HttpContext,RequestContext和ControllerContext来实现它,注册路由,然后用这些路由创建一个UrlHelper

有点像这样:

public static void SetFakeControllerContext(this Controller controller, HttpContextBase httpContextBase)
{
    var httpContext = httpContextBase ?? FakeHttpContext().Object;
    var requestContext = new RequestContext(httpContext, new RouteData());
    var controllerContext = new ControllerContext(requestContext, controller);
    MvcApplication.RegisterRoutes();
    controller.ControllerContext = controllerContext;
    controller.Url = new UrlHelper(requestContext, RouteTable.Routes);
}

FakeHttpContext()是一个Moq帮助器,它可以创建所有模拟的东西,服务器变量,会话等。


UrlHelper的构造函数将RouteCollection作为第二个参数。 如果你有MVC为你创建的默认设置,那么我认为这应该适合你:

var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);

controller.Url = new UrlHelper(fakeRequestContext, routes);

另一种方法是修改应用程序的启动方式,使测试和使用起来更容易一些。 如果你定义和界面如下所示:

public interface IMvcApplication
{
    void RegisterRoutes(RouteCollection routes);
    // Other startup operations    
}

通过实施:

public class MyCustomApplication : IMvcApplication
{
    public void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        // Your route registrations here
    }

    // Other startup operations
}

然后你可以像这样修改你的Global.asax

public class MvcApplication : HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        var app = new MyCustomApplication();
        app.RegisterRoutes(RouteTable.Routes);
        // Other startup calls
    }
}

并且仍然可以灵活地注册您的路线进行测试。 像这样的东西:

private IMvcApplication _app;
private RouteCollection _routes;

[TestInitialize]
public void InitializeTests()
{
    _app = new MyCustomApplication();

    _routes = new RouteCollection();
    _app.RegisterRoutes(_routes);
}

这同样可以用于区域注册。

private RouteCollection _routes;
private MyCustomAreaRegistration _area;

[TestInitialize]
public void InitTests()
{
    _routes = new RouteCollection();
    var context = new AreaRegistrationContext("MyCustomArea", _routes);

    _area.RegisterArea(context);
}

因为这是一个测试,所以您的测试套件很可能不像您所期望的那样读取Global.asax。

为了解决这个问题,请执行@ataddeini建议的操作并创建一个路由集合。 在这个集合中添加一个新的路线,它看起来像......

var routes = new RouteCollection();
routes.Add(new Route("Landing_Page", new { /*pass route params*/}, null));
var helper = new UrlHelper(fakeRequestContext, routes);
链接地址: http://www.djcxy.com/p/57851.html

上一篇: ASP.NET MVC Controller Unit Testing

下一篇: Using Ajax.BeginForm with ASP.NET MVC 3 Razor