ASP.NET MVC2 自定义视图引擎在单元测试中被忽略
我正在尝试对将数据填充到 ViewData 中的控制器进行单元测试。我们所有的视图都需要类似的数据(从 url 派生的客户信息)。因此,最初的开发人员没有将调用放入每个控制器方法中,而是选择将此 ViewData 填充到 OnActionExecuting 事件中。
当然,当您从单元测试调用控制器的操作时,OnActionExecuting 不会触发。 (感谢 MVC 团队!)
因此,我尝试创建一个自定义视图引擎,并在请求视图时将客户数据填充到controllerContext 中。这在浏览器中工作正常,但当我运行此测试时,我的 viewEngine 被忽略。再多的 ViewEngines.Add(new funkyViewEngine) 也没有任何效果。
[TestMethod()]
public void LoginTest()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new FunkyViewEngine());
UserController target = new UserController();
target.SetStructureMap(); <--sets us to use the test repo
target.ControllerContext.HttpContext = MVCHelpers.FakeHttpContext("https://customersubdomain.ourdomain.com"); <--moq magic
var actual = target.Login();
Assert.IsTrue(actual.GetType().IsAssignableFrom(typeof(System.Web.Mvc.ViewResult)));
var vr = actual as ViewResult;
Assert.IsTrue(vr.ViewData.Community() != null); <--"Community" should be set by viewengine
Assert.IsTrue(vr.ViewData.Community().Subdomain == "customersubdomain.ourdomain");
Assert.IsTrue(vr.ViewData.Community().CanRegister);
}
这里还有希望吗?我如何 1) 创建一个在浏览器和单元框架中的控制器执行时调用的方法,或者 2) 让单元框架调用我的视图引擎。
I'm trying to unit test a controller that stuffs data into a ViewData. All our views require similar data (Customer info which is derived from the url). So instead of putting the call into every single controller method, the original developers chose to put this ViewData stuffing into the OnActionExecuting event.
Of course, when you invoke the controller's action from a unit test, OnActionExecuting doesn't fire. (Thanks MVC Team!)
So I tried creating a custom view engine and having it stuff the customer data into the controllerContext when the view is requested. This works fine in a browser, but my viewEngine is ignored when I run this test. No amount of ViewEngines.Add(new funkyViewEngine) has any effect.
[TestMethod()]
public void LoginTest()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new FunkyViewEngine());
UserController target = new UserController();
target.SetStructureMap(); <--sets us to use the test repo
target.ControllerContext.HttpContext = MVCHelpers.FakeHttpContext("https://customersubdomain.ourdomain.com"); <--moq magic
var actual = target.Login();
Assert.IsTrue(actual.GetType().IsAssignableFrom(typeof(System.Web.Mvc.ViewResult)));
var vr = actual as ViewResult;
Assert.IsTrue(vr.ViewData.Community() != null); <--"Community" should be set by viewengine
Assert.IsTrue(vr.ViewData.Community().Subdomain == "customersubdomain.ourdomain");
Assert.IsTrue(vr.ViewData.Community().CanRegister);
}
Is there any hope here? How do I either 1) create a method that gets called on controller execution BOTH in the browser and the unit framework or 2) get the unit framework to invoke my view engine.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
很抱歉让您感到沮丧。当您直接从单元测试中调用操作方法时,您看到
OnActionExecuting
未被调用的原因是因为这不是 MVC 中的工作方式。该请求通过“管道”执行,就该区域而言,该管道由
ControllerActionInvoker
组成。该类负责:OnActionExecuting
方法(注意: 您的控制器类也是一个操作过滤器)OnActionExecuted
方法在单元测试中,您直接调用步骤 3,并跳过所有其他步骤。在单元测试中,您有责任调用您的操作正常运行所需的任何设置代码。
但是,这并不意味着您现在应该编写使用
ControllerActionInvoker
执行整个管道的单元测试。我们(MVC 团队)已经验证了所有部分都可以协同工作。相反,您应该测试您的特定应用程序代码。在这种情况下,您可能会考虑进行以下单元测试:
OnActionExecuting
的测试是否将正确的 Customer 对象放入 ViewData我的最后一点是,您应该将功能保留在
OnActionExecuting
中。自定义视图引擎绝对是错误的地方。Sorry for your frustration. The reason why you are seeing
OnActionExecuting
not being called when you directly call your action method from the unit test is because that's not how things work in MVC.The request gets executed via a "pipeline", which as far as this area is concerned consists of the
ControllerActionInvoker
. This class is responsible for:OnActionExecuting
method (note: your controller class is also an action filter)OnActionExecuted
methodIn your unit test you are directly invoking step 3. and skipping all the other steps. In a unit test, it is your responsibility to call any setup code required for your action to work.
However, this does not mean you should now write unit tests that use the
ControllerActionInvoker
to execute the entire pipeline. We (the MVC team) have already verified that all the pieces work together.Instead, you should test your specific application code. In this case, you might consider having the following unit tests:
OnActionExecuting
on your controller puts the right Customer object into ViewDataMy last point is that you should keep the functionality in
OnActionExecuting
. A custom view engine is definetely the wrong place for it.这不是您可能正在寻找的答案,但我正在使用自定义 MvcHandler 来实现相同的目标(从多租户应用程序中的 URL 获取客户)。对我来说,ViewEngine 听起来不像是这种逻辑的好地方...
我的自定义处理程序看起来或多或少像这样:
Not an answer you're probably looking for, but I'm using a custom MvcHandler to achieve the same goal (getting customer from URL in multi-tenant app). ViewEngine doesn't sound like a good place for this kind of logic to me...
My custom handler looks more or less like this: