简体   繁体   English

如何将控制器与过滤器一起单元测试(带有autofac的ASP.NET MVC)

[英]How can I unit test controller together with a filter (ASP.NET MVC with autofac)

so I am writing a high-level unit test in ASP.NET MVC 4 using autofac. 所以我正在使用autofac在ASP.NET MVC 4中编写高级单元测试。

So I have a sample controller: 所以我有一个样本控制器:

    public class SomeController
    {        
        [SomeFilter]
        public ActionResult SomeAction()
        {
            SomeCode();
        }
    }

And I can write a sample test: 我可以写一个样本测试:

    [Test]
    public void Test()
    {
        var controller = new SomeController();
        var result = controller.SomeAction();
        // Asserts go here
    }

That all works great, provided I fake out all external dependencies. 只要我伪造出所有外部依赖关系,这一切都很有效。 However, there is also some code that is attached via filter attribute that I would like to run (it is important to this test, and I do not want to just test it in isolation). 但是,还有一些代码通过我希望运行的filter属性附加(这对于此测试很重要,我不想只是单独测试它)。

This code would be executed when run within the application, but it would not be executed if run within the test. 此代码将在应用程序中运行时执行,但如果在测试中运行则不会执行。 It does not matter if I new up controller manually, or retrieve it using DependencyResolver as: 如果我手动启动控制器,或使用DependencyResolver检索它,则无关紧要:

var someController = DependencyResolver.Current.GetService<SomeController>();

This is obviously because during normal run-time the framework creates and attaches those filters properly. 这显然是因为在正常运行时,框架会正确创建和附加这些过滤器。

So the question is - how could I duplicate this behavior in the test and have those action filters executed? 所以问题是 - 如何在测试中复制此行为并执行这些操作过滤器?

Good Morning Sebastian, 早安塞巴斯蒂安,

For reasons beyond posting here I had to write unit tests to utilize the action filter along with the web api controller end point. 由于此处发布的原因,我不得不编写单元测试以使用动作过滤器以及web api控制器端点。

Of course as you observed and I found out as well the action filters do not fire during a unit test. 当然,正如您观察到的那样,我发现动作过滤器在单元测试期间不会触发。

I hacked my way to this solution but am definitely open to further education. 我讨厌这个解决方案,但我肯定对接受进一步的教育持开放态度。

In my unit test I am using a fluent builder pattern but in short spin up your controller. 在我的单元测试中,我使用的是流畅的构建器模式,但总之是旋转控制器。 (BTW if you want more info on a fluent builder pattern just post a comment and I'll pass along links...that or Google it.) (顺便说一句,如果你想要更多关于流畅的建设者模式的信息,只需发表评论,我会传递链接......或谷歌。)

//we need to setup some context stuff that you'll notice is passed 
//in to the builder WithControllerContext...and then the controller is 
//used to get the ActionFilter primed

//0. Setup WebApi Context
var config = new HttpConfiguration();
var route = config.Routes.MapHttpRoute("DefaultSlot", "cars/_services/addPickup");
var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", "AddPickup" } });


var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:24244/cars/_services/addPickup");
request.RequestUri = new Uri("http://localhost:24244/cars/_services/addPickup");
List<string> x = new List<string>() { MediaType.CarsV2.GetDescription() };
request.Headers.Add("Accept", x);


 ....obviously 1 & 2 I skipped as they aren't relevant


//3. controller
PickupController controller = new PickupControllerBuilder()
//.MoqReqHlpr_IsAny_CreateResp(HttpStatusCode.OK) //3a. setup return message
.MoqCarRepoAny_ReturnsSampleDataCar(new Guid("000...0011")) //3b. car object
.MoqFulfillRepoAnyCar_IsAny_IsQuickShop(true) //3c. fulfillment repository
.MoqCartRepoAnyCar_IsAny_UpdateCar(true) //3d. car repository
.WithControllerContext(config, routeData, request)
.WithHttpPropertyKey(lsd);


//HttpActionContextFilter is the name of my ActionFilter so as you can
//see we actually instantiate the ActionFilter then hook it to the
//controller instance
var filter = new HttpActionContextFilter();
filter.OnActionExecuting(controller.ActionContext);

Two things to note that bit me. 咬我的两件事要注意。

  1. make sure you have the correct namespace. 确保你有正确的命名空间。 I let VS import it via Ctrl-. 我让VS通过Ctrl-导入它。 and of course it imported System.Web.Mvc and I needed System.Web.Http. 当然它导入了System.Web.Mvc,我需要System.Web.Http。
  2. You need to hook the overrides you want to fire. 你需要挂钩你想要触发的覆盖。 So if your action filter has four overrides then you need to hook four times. 因此,如果您的动作过滤器有四个覆盖,那么您需要挂钩四次。 If you have multiple ActionFilters then you need to instantiate each and hook its overrides. 如果你有多个ActionFilters,那么你需要实例化每个并挂钩它的覆盖。

I included the screenshot thinking a picture would be helpful here. 我提供了截图,认为图片在这里会有所帮助。

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM