MVC3 HttpContext 单元测试/模拟选项
所以这确实适用于几个不同的类,如 HttpContext、ConfigurationManager 等。有几种不同的方法可以处理这个问题,我一直使用包装类来处理这些东西,但我想看看最常见的社区实践是什么。 包装器类 - 例如,
- 我将有一个 HttpContextService,我通过构造函数传入它,该构造函数通过平面方法调用公开所有相同的功能。
- 包装类(第 2 部分) - 例如,我将拥有特定的服务类,例如 MembershipService,它在幕后利用 HttpContext。功能与 1 相同,但命名方案/使用模式略有不同,因为您是通过特定服务而不是单一包装器公开特定功能。缺点是需要注入的服务类的数量会增加,但是当您不需要整体包装器的所有功能时,您可以获得一些模块化。
- ActionFilters 和参数 - 使用 ActionFilter 自动传入每个函数所需的某些值。仅限 MVC,并限制您使用控制器方法,而 1 和 2 可以在整个项目中通用,甚至可以与此选项结合使用。
- 直接模拟 HttpContextBase 并设置 ControllerContext - 有几种模拟框架扩展方法可以帮助解决此问题,但本质上要求您直接根据需要进行设置。不需要抽象,这很好,并且也可以在非控制器测试中重用。不过,对于 ConfigurationManager 和其他静态方法调用仍然存在悬而未决的问题,因此您最终可能会以任何方式注入,但会以其他方式访问 HttpContext。
现在我正在做第 1 点,所以我有一个 HttpContextService 和一个 ConfigurationManagerService 等,然后我将它们注入,尽管我将来倾向于第 2 点。 3 对于我的口味来说似乎有点太混乱了,但我可以看到控制器方法的吸引力,并且需要为也使用这些静态类的其他代码区域提供完全独立的解决方案,这对我来说是一种穷人。 .. 4 对我来说仍然很有趣,因为它在基本功能方面似乎是最“自然”的,并且利用了 MVC 的内置方法。
那么这里流行的最佳实践是什么?人们在野外看到和使用什么?
So this really applies to several different classes like HttpContext, ConfigurationManager, etc. There are several different ways to handle this, and I have always used wrapper classes to handle this stuff, but I wanted to see what the most common community practice is...
- Wrapper classes - e.g. I would have an HttpContextService which I pass in via constructor that exposes all the same functionality via flat method calls.
- Wrapper classes (part 2) - e.g. I would have SPECIFIC service classes, like MembershipService, which LEVERAGES HttpContext behind the scenes. Functions the same as 1, but the naming scheme / usage pattern is a little different as you are exposing specific functions through specific services instead of one monolithic wrapper. The downside is that the number of service classes that need to be injected goes up, but you get some modularity for when you don't need all the features of the monolithic wrapper.
- ActionFilters and parameters - Use an ActionFilter to automatically pass in certain values needed on a per function basis. MVC only, and limits you to the controller methods, whereas 1 and 2 could be used generically throughout the project, or even in conjunction with this option.
- Directly mocking HttpContextBase and setting ControllerContext - There are several mocking framework extension methods out there to help with this, but essentially requires you to directly set things as needed. Doesn't require abstractions, which is nice, and can be reused across non-controller tests as well. Still leaves open the question for ConfigurationManager and other static method calls though, so you could end up with injecting that ANYWAY, but leaving HttpContext to be accessed in this other way.
Right now I am kind of doing number 1, so I have an HttpContextService and a ConfigurationManagerService, etc. which I then inject, though I'm leaning toward 2 in the future. 3 seems to be a little too messy for my tastes, but I can see the appeal for controller methods, and the need for a completely separate solution for other areas of code that also use these static classes makes that one kind of poor for me... 4 is still interesting to me as it seems the most "natural" in terms of basic functionality and leverages the built-in methodologies of MVC.
So what is the prevailing Best Practice here? What are people seeing and using in the wild?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
已经有 HttpContext、HttpRequest、HttpResponse 等的“包装”类。MVC 框架使用这些类,您可以通过控制器上下文向控制器提供它们的模拟。您不需要模拟控制器上下文,因为您可以简单地使用适当的值创建一个控制器上下文。我发现唯一难以模拟的是助手 UrlHelper 和 HtmlHelper。这些有一些相对较深的依赖关系。您可以以某种合理的方式伪造它们,如下所示的 UrlHelper。
在哪里
There are already "wrapper" classes for HttpContext, HttpRequest, HttpResponse, etc. The MVC framework uses these and you can supply mocks of them to the Controller via the controller context. You don't need to mock the controller context as you can simply create one with the appropriate values. The only thing I've found difficult to mock are the helpers, UrlHelper and HtmlHelper. Those have some relatively deep dependencies. You can fake them in a somewhat reasonable way, UrlHelper shown below.
where