Get view name where ViewResult.ViewName is an empty string for Unit Testing

I wrote an extension method for ActionResult for use in unit testing, which will claim whether the ViewName returned as expected. This is the code that I still have:

public static void AssertViewWasReturned(this ActionResult result, string viewName) { string actualViewName; if (result is ViewResult) actualViewName = (result as ViewResult).ViewName; else if (result is PartialViewResult) actualViewName = (result as PartialViewResult).ViewName; else throw new InvalidOperationException("Results of type " + result.GetType() + " don't have a ViewName"); Assert.AreEqual(viewName, actualViewName, string.Format("Expected a View named{0}, got a View named {1}", viewName, actualViewName)); } 

This works fine unless the controller returns the view without specifying a name — in this case, result.ViewName is an empty string.

So my question is: is there any information from the ViewResult object, what is the name of the view, where ViewName is an empty string?

+4
source share
6 answers

If your controller method is not called through the MVC pipeline, additional information is not added to the Controller.ViewData dictionary (which, as I assumed, will somehow provide a "key" action, but cannot confirm). But since you use your controller “outside” the context of the routing structure, etc., It does not know about the method being called.

So the answer is simply no. If the view name is not specified, you cannot determine it from the ViewResult returned by the action. At least not in how your controller is tested (which is quite handy).

+5
source

For what it's worth - I revised my test, my extension method similar to this (including J. Tikhon's feedback):

 public static void AssertViewWasReturned(this ActionResult result, string viewName, string defaultViewName) { Assert.IsInstanceOf<ViewResultBase>(result, "Result is not an instance of ViewResultBase"); var viewResult = (ViewResultBase)result; var actualViewName = viewResult.ViewName; if (actualViewName == "") actualViewName = defaultViewName; Assert.AreEqual(viewName, actualViewName, string.Format("Expected a View named{0}, got a View named {1}", viewName, actualViewName)); } 

This means that my unit tests may contain code like this:

 var result = controller.MyAction(); result.AssertViewWasReturned("ExpectedViewName","MyAction") 

This is not as good as I hoped, since I need to specify "defaultViewName" (ie the name of the action), but this is a reasonable amount.

+3
source

You can update your controllers to always transmit the required view.

Instead:

 public ActionResult Index() { return View(); } 

Do this instead:

 public ActionResult Index() { return View("Index"); } 

Either this, or change the unit test code.

+2
source

I'm not sure I understand your question, but if the View() method is called without parameters, MVC will look for the view with the name of the calling method in a directory called the controller (without "Controller" added to the name).

For example, this action:

 public class UserController : Controller { public ActionResult SomeAction() { // some code here return View(); } } 

Since this is an empty call to View() , MVC will look for the view with the path and file name ~\Views\User\SomeAction.cshtml .

Does this answer your question?

+1
source

When you return, you must call your view name.

Example:

 Public ActionResult Index(){ // your code Return View("YourViewName", DataToSendForView); } 
+1
source

You can override the controller. The OnResultExecuted method is the controller lifecycle point where there is an available view.

 protected override void OnResultExecuted(ResultExecutedContext ctx) { base.OnResultExecuted(ctx); String ViewPath = ((System.Web.Mvc.BuildManagerCompiledView)((System.Web.Mvc.ViewResultBase)ctx.Result).View).ViewPath.ToString(); } 
0
source

Source: https://habr.com/ru/post/1383507/


All Articles