我正在对我的标准进行一些简单的MS单元测试,没有什么特殊的控制器。
当我从返回的ViewName
对象中检查ViewResult
属性时,它是""
(空)。
我的印象是ViewName
的名称隐含View
(在ASP.NET MVC控制器测试中为suggested by this MS article)。
BTW,当我测试ViewData时,它就在那里并且正确。
这是我的代码......
public ActionResult Index(int? page, string tag)
{
if (page == null || page <= 0)
{
page = 1;
}
var viewData = new IndexViewData
{
... my property setters, etc ...
};
return View(viewData);
}
[TestMethod]
public void Index_Action_Should_Return_Index_View_For_Default_HomePage()
{
// Arrange.
var controller = PostController; // Wrapper, cause I use D.I.
// Act.
ViewResult viewResult = controller.Index(null, null) as ViewResult;
// Assert.
Assert.IsNotNull(viewResult);
Assert.AreEqual("Index", viewResult.ViewName); // This is false/fails.
var indexViewData = viewResult.ViewData.Model as IndexViewData;
Assert.IsNotNull(indexViewData); // This is true.
}
答案 0 :(得分:28)
只有在ViewResult中设置ViewName时才会出现。如果您的视图名称与您的控制器名称匹配,那么我将检查以确保ViewName为null或为空,因为您将不希望在视图上设置名称(IMO)正确的行为。我只检查ViewName是否已设置,当我打算返回的视图与操作不匹配时 - 例如,返回“错误”视图时,例如。
编辑:以下是ViewResultBase.cs中ExecuteResult的来源(来自RC1,我的Macintosh上没有RTW源)。正如您所看到的,它会检查是否已直接设置ViewName,如果没有,则将其从控制器上下文的路由数据中的操作中提取出来。这只发生在ExecuteResult中,在控制器的操作完成后调用它。
public override void ExecuteResult(ControllerContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
if (String.IsNullOrEmpty(ViewName)) {
ViewName = context.RouteData.GetRequiredString("action");
}
ViewEngineResult result = null;
if (View == null) {
result = FindView(context);
View = result.View;
}
ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);
View.Render(viewContext, context.HttpContext.Response.Output);
if (result != null) {
result.ViewEngine.ReleaseView(context, View);
}
}
答案 1 :(得分:2)
我个人发现MVC2提供的测试设备有点笨拙。我猜测已经存在一些更好的东西了,但我最终创建了一个简单的类来测试动作。我在一个名为MockRoundTrip
的优秀开源Java MVC framework Stripes提供的类上建模了界面(实现是另一个故事)。
以下是测试操作时用于获取操作目标页面的方法,称为getTripDestination()
。无论视图名是否明确设置,它都会返回正确的结果
//Get the destination page of the request, using Runtime execution pattern of MVC, namely
//if no ViewName is explicitly set in controller, ViewResult will have an empty ViewName
//Instead, current action name will be used in its place
public string getTripDestination()
{
RouteData routeData = getRouteData();
ViewResult viewResult = (result is ViewResult) ? (ViewResult)result : null;
string tripDestination = (viewResult != null) ? viewResult.ViewName : "";
return (tripDestination != "") ? tripDestination : (String)routeData.Values["action"];
}
private RouteData getRouteData()
{
HttpContextBase context = controller.ControllerContext.RequestContext.HttpContext;
return RouteTable.Routes.GetRouteData(context);
}
答案 2 :(得分:0)
视图名由框架自动设置。但是当我们进行单元测试时,我们将框架短路,并且没有任何东西可以设置名称。
因此我们的操作需要在单元测试时明确设置视图名。如果我们确实真的想要依靠惯例,我们也可以检查null或为空。
答案 3 :(得分:0)
documentation for Controller.View()州:
View类的此方法重载返回一个ViewResult对象 具有空ViewName属性。如果你正在编写单元测试 控制器动作,考虑到空的ViewName属性 不采用字符串视图名称的单元测试。
在运行时,如果ViewName属性为空,则为当前操作 name用于代替ViewName属性。
因此,当期望与当前操作同名的视图时,我们可以测试它是否为空字符串。
或者,Controller.View(String)方法将设置ViewName。