English 中文(简体)
单位测试伙伴关系。 NET MVC 2航道,在区区进行救助。 登记册
原标题:Unit testing ASP.NET MVC 2 routes with areas bails out on AreaRegistration.RegisterAllAreas()

I m 单位检测了我在ASP的路线。 NET MVC 2. Im使用MS 测试,Im 使用地区。

[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.Register AllAreas(,它就放弃了这一例外:

System.InvalidOperation 例外:制度。 无效行动 例外: 这种方法不能在申请启动前启动阶段使用。

因此,我不认为我可以从我的班子初始手提这个问题。 但can 我称之为吗? 我在试验中显然没有<代码>Application_Start。

最佳回答

我通过创建我的<条码>AreaRegistration类别,并使用<条码>RegisterArea方法解决了这一问题。

例如,鉴于“Catalog”这一路线:

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"]);
}
问题回答

我在这里很想知道我的chim,但我刚刚亲自通过这一问题。 类似解决办法如Jason(当时对一个地区进行登记),但与你一样,使用MvcContrib。 测试Helper不做我自己的 mo弄。

[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,但Im的罚款加上Rhino dll,只是为了获得这一冰功能。

检测项目没有位置,你可以将地区重新定位。 登记册系统; 系统。 Web.Compilation。 编制网站代码的建筑群分类,如果在伙伴关系之外使用,则治理失败。 NET管道。 我认为,它会带来一种ug,因为它是真实的,使测试很难进行。

但是,我发明了两点工作:

第一,修改 App.Config file of their test Project

<?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>

Actualy you should refference all assemblies that contains AreaRegistration descenders. Second add this ugly code before 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);

仅用于4.0和4.0及以上。

为了让地区登记,Register AllAreas()首先实施以下守则:

请注意<代码>类型(YourMvcSiteApplication)。 大会:

    object manager = typeof(BuildManager).GetField("_theBuildManager", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
    manager.SetField("_skipTopLevelCompilationExceptions", true);
    manager.SetField("_topLevelFilesCompiledStarted", true);
    manager.SetField("_topLevelReferencedAssemblies", new List<Assembly> { typeof(YourMvcSiteApplication).Assembly });

此处是分门标的延伸方法:

    public static void SetField<T>(this object source, string fieldName, T value)
    {
        var type = source.GetType();
        var info = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        if (info != null)
        {
            info.SetValue(source, value);
        }
    }

以上编码为:NET 3.5,I haven t test for .NET 4 or 4.5 ,但!

这是两年的晚期,但我的数字是我的份额。 我用反思对所有地区进行登记。

public void RegisterAllAreas()
{
    List<AreaRegistration> objects = new List<AreaRegistration>();

    foreach (Type type in Assembly.GetAssembly(typeof(MvcApplication)).GetTypes()
            .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(AreaRegistration))))
    {
        objects.Add((AreaRegistration)Activator.CreateInstance(type));
    }

    objects.ForEach(area => area.RegisterArea(new AreaRegistrationContext(area.AreaName, routes)));
}

这里有一套综合方法的冰版。

用于:


[TestClass]
public class RoutesTest : RoutesTestClassBase<SomeAreaRegistration>
{
    [TestMethod]
    public void IdWithoutName()
    {
        // Area-Name is retrieved from the Registration 
        // and prepended as "~/AreaName/"

        TestRoute("Contacts/Show/0627ED05-BF19-4090-91FC-AD3865B40983", new { 
            controller = "Contacts", 
            action = "Show",
            id = "0627ED05-BF19-4090-91FC-AD3865B40983"
        });
    }

    [TestMethod]
    public void IdAndName()
    {
        TestRoute("Contacts/Show/0627ED05-BF19-4090-91FC-AD3865B40983-Some-name", new
        {
            controller = "Contacts",
            action = "Show",
            id = "0627ED05-BF19-4090-91FC-AD3865B40983",
            name= "Some-name"
        });
    }
}

2. 基础构造:

public class RoutesTestClassBase<TAreaRegistration>
{
    protected void TestRoute(string url, object expectations)
    {
        var routes = new RouteCollection();
        var areaRegistration = (AreaRegistration)Activator.CreateInstance(typeof(TAreaRegistration));

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

        url = "~/" + areaRegistration.AreaName + "/" + url;

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

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

        Assert.IsNotNull(routeData, "Should have found the route");
        Assert.AreEqual(areaRegistration.AreaName, routeData.DataTokens["area"]);

        foreach (PropertyValue property in GetProperties(expectations))
        {
            Assert.IsTrue(string.Equals(property.Value.ToString(),
                routeData.Values[property.Name].ToString(),
                StringComparison.OrdinalIgnoreCase)
                , string.Format("Expected  {0} , not  {1}  for  {2} .",
                property.Value, routeData.Values[property.Name], property.Name));
        }
    }

    private static IEnumerable<PropertyValue> GetProperties(object o)
    {
        if (o != null)
        {
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(o);
            foreach (PropertyDescriptor prop in props)
            {
                object val = prop.GetValue(o);
                if (val != null)
                {
                    yield return new PropertyValue { Name = prop.Name, Value = val };
                }
            }
        }
    }

    private sealed class PropertyValue
    {
        public string Name { get; set; }
        public object Value { get; set; }
    }
}




相关问题
Manually implementing high performance algorithms in .NET

As a learning experience I recently tried implementing Quicksort with 3 way partitioning in C#. Apart from needing to add an extra range check on the left/right variables before the recursive call, ...

Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

How do I compare two decimals to 10 decimal places?

I m using decimal type (.net), and I want to see if two numbers are equal. But I only want to be accurate to 10 decimal places. For example take these three numbers. I want them all to be equal. 0....

Exception practices when creating a SynchronizationContext?

I m creating an STA version of the SynchronizationContext for use in Windows Workflow 4.0. I m wondering what to do about exceptions when Post-ing callbacks. The SynchronizationContext can be used ...

Show running instance in single instance application

I am building an application with C#. I managed to turn this into a single instance application by checking if the same process is already running. Process[] pname = Process.GetProcessesByName("...

How to combine DataTrigger and EventTrigger?

NOTE I have asked the related question (with an accepted answer): How to combine DataTrigger and Trigger? I think I need to combine an EventTrigger and a DataTrigger to achieve what I m after: when ...

热门标签