Маршруты поблочного тестирования ASP.NET MVC 2 с областями прыгают с парашютом на AreaRegistration. RegisterAllAreas ()

Я - поблочное тестирование мои маршруты в ASP.NET MVC 2. Я использую MSTest, и я использую области также.

[TestClass]
public class RouteRegistrarTests
{
    [ClassInitialize]
    public static void ClassInitialize(TestContext testContext)
    {
        RouteTable.Routes.Clear();

        RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        RouteTable.Routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });

        AreaRegistration.RegisterAllAreas();

        routes.MapRoute(
            "default",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

    [TestMethod]
    public void RouteMaps_VerifyMappings_Match()
    {
        "~/".Route().ShouldMapTo<HomeController>(n => n.Index());
    }
}

Когда это выполняется AreaRegistration.RegisterAllAreas() однако, это выдает это исключение:

Система. InvalidOperationException: Система. InvalidOperationException: Этот метод нельзя назвать во время этапа инициализации приложения перед запуском.

Так, я считаю, что не могу назвать его от своего инициализатора класса. Но когда я могу назвать его? Я, очевидно, не имею Application_Start в моем тесте.

20
задан Sandor Drieënhuizen 26 April 2010 в 19:29
поделиться

4 ответа

Я решил эту проблему, создав экземпляр моего класса AreaRegistration и вызвав метод RegisterArea .

Например, дана Область с именем «Каталог» с этим маршрутом:

public override void RegisterArea(AreaRegistrationContext context)
{
  context.MapRoute(
      "Catalog_default",
      "Catalog/{controller}/{action}/{id}",
      new {controller = "List", action = "Index", id = "" }
  );
}

Это мой метод тестирования:

[TestMethod]
public void TestCatalogAreaRoute()
{
  var routes = new RouteCollection();

  // Get my AreaRegistration class
  var areaRegistration = new CatalogAreaRegistration();
  Assert.AreEqual("Catalog", areaRegistration.AreaName);

  // Get an AreaRegistrationContext for my class. Give it an empty RouteCollection
  var areaRegistrationContext = new AreaRegistrationContext(areaRegistration.AreaName, routes);
  areaRegistration.RegisterArea(areaRegistrationContext);

  // Mock up an HttpContext object with my test path (using Moq)
  var context = new Mock<HttpContextBase>();
  context.Setup(c => c.Request.AppRelativeCurrentExecutionFilePath).Returns("~/Catalog");

  // Get the RouteData based on the HttpContext
  var routeData = routes.GetRouteData(context.Object);

  Assert.IsNotNull(routeData, "Should have found the route");
  Assert.AreEqual("Catalog", routeData.DataTokens["area"]);
  Assert.AreEqual("List", routeData.Values["controller"]);
  Assert.AreEqual("Index", routeData.Values["action"]);
  Assert.AreEqual("", routeData.Values["id"]);
}
28
ответ дан 29 November 2019 в 22:58
поделиться

Я думаю, вы ищете класс TestHelper в библиотеке MVC Contrib. Взгляните на тесты в MVC Contrib (он там спрятан). Вы обнаружите, что все красиво имитировано. H

MVCContrib.UnitTests \ TestHelper \ RoutesTest.cs - необходимо обновить вики! Удачи

using System.Web.Mvc;
using System.Web.Routing;
using NUnit.Framework;

namespace MVCContrib.Application.UnitTests.TestHelper
{
    /// <summary>
    /// Summary description for UserRoutesTest
    /// </summary>
    [TestFixture]
    public class UserRoutesTest
    {
        [TestFixtureSetUp]
        public void Setup()
        {
            var routes = RouteTable.Routes;
            routes.Clear();
            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}",                                         // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
                );

        }

        [Test]
        public void homeIndex()
        {
            "~/user"
                .ShouldMapTo<HomeController>(action => action.Index());
        }


        [Test]
        public void HomeShow()
        {
                         "~/home"
                           .GivenIncomingAs(HttpVerbs.Put)
                           .ShouldMapTo<HomeController>(action => action.Index());
        }

    }
}
1
ответ дан 29 November 2019 в 22:58
поделиться

Ну нет места в тестовом проекте, где можно поставить AreaRegistration.RegisterAllAreas (); чтобы заставить его работать, потому что он использует класс System.Web.Compilation.BuildManager для компиляции кода для веб-сайта и не работает, если он вызывается вне конвейера ASP.NET. Я думаю, что это своего рода ошибка, потому что она действительно затрудняет выполнение тестов.

Но я изобрел двухэтапный обходной путь :)

Сначала вы должны изменить файл App.Config вашего тестового проекта.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>

    </appSettings>

    <connectionStrings>

    </connectionStrings>
    <system.web>
        <compilation debug="true">
            <assemblies>
                <add assembly="!!!NAME_OF_YOUR_MVC_WEB_ASSEMBLY!!!"/>       
            </assemblies>
        </compilation>
    </system.web>
    </configuration>

На самом деле вы должны ссылаться на все сборки, которые содержат нисходящие элементы AreaRegistration. Второе добавление этот уродливый код перед AreaRegistration.RegisterAllAreas ();

typeof(BuildManager).GetProperty("PreStartInitStage", BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, 2, null);

typeof(BuildManager).GetField("_topLevelFilesCompiledStarted", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(   typeof(BuildManager).GetField("_theBuildManager", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null), true);

Это работает только для .Net 4.0 и выше

10
ответ дан 29 November 2019 в 22:58
поделиться

Я знаю, что вступаю здесь с опозданием, но я только что сам решал эту проблему. Решение аналогично Джейсону (регистрировать по одной области за раз), но, как и вы, я использую MvcContrib.TestHelper вместо того, чтобы делать свой собственный mocking.

[TestInitialize]
public void Setup() {
    RouteTable.Routes.Clear();
    var areaReg = new AdminAreaRegistration();
    areaReg.RegisterArea(new AreaRegistrationContext(areaReg.AreaName, RouteTable.Routes));
}

[TestMethod]
public void admin_should_map_to_home() {
    "~/Admin".ShouldMapTo<HomeController>(c => c.Index());
}

Обратите внимание, что MvcContrib имеет жесткую зависимость от Rhino Mocks. Хотя я предпочитаю использовать Moq, я не против включить Rhino dll только для того, чтобы получить эту приятную функциональность.

11
ответ дан 29 November 2019 в 22:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: