27

I'm writing a unit test and I call an action method like this

var result = controller.Action(123);

result is ActionResult and I need to get the model somehow, anybody knows how to do this?

Richard Ev
  • 52,939
  • 59
  • 191
  • 278
Omu
  • 69,856
  • 92
  • 277
  • 407

4 Answers4

34

In my version of ASP.NET MVC there is no Action method on Controller. However, if you meant the View method, here's how you can unit test that the result contains the correct model.

First of all, if you only return ViewResult from a particular Action, declare the method as returning ViewResult instead of ActionResult.

As an example, consider this Index action

public ViewResult Index()
{
    return this.View(this.userViewModelService.GetUsers());
}

you can get to the model as easily as this

var result = sut.Index().ViewData.Model;

If your method signature's return type is ActionResult instead of ViewResult, you will need to cast it to ViewResult first.

Community
  • 1
  • 1
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • 5
    It's better to cast to ViewResultBase (this covers partials); also (rarely) one may consider using reflection to check ViewData/Model properties and get Model (in case there're unknown view result types). – queen3 Jan 15 '10 at 13:29
  • 1
    Good point on ViewResultBase, but why would you ever use Reflection for something like this? – Mark Seemann Jan 15 '10 at 14:16
20

We placed the following piece in a testsbase.cs allowing for typed models in the tests a la

ActionResult actionResult = ContextGet<ActionResult>();
var model = ModelFromActionResult<SomeViewModelClass>(actionResult);

ModelFromActionResult...

public T ModelFromActionResult<T>(ActionResult actionResult)
{
    object model;
    if (actionResult.GetType() == typeof(ViewResult))
    {
        ViewResult viewResult = (ViewResult)actionResult;
        model = viewResult.Model;
    }
    else if (actionResult.GetType() == typeof(PartialViewResult))
    {
        PartialViewResult partialViewResult = (PartialViewResult)actionResult;
        model = partialViewResult.Model;
    }
    else
    {
        throw new InvalidOperationException(string.Format("Actionresult of type {0} is not supported by ModelFromResult extractor.", actionResult.GetType()));
    }
    T typedModel = (T)model;
    return typedModel;
}

An example using a Index page and List:

var actionResult = controller.Index();
var model = ModelFromActionResult<List<TheModel>>((ActionResult)actionResult.Result);
Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
Max
  • 3,280
  • 2
  • 26
  • 30
  • 3
    Great I combined it with http://mkramar.blogspot.com.au/2012/06/onactionexecuting-and-onactionexecuted.html (from http://stackoverflow.com/questions/591720/how-do-i-unit-test-my-asp-net-mvc-controllers-onactionexecuting-method) So it looks like: ActionResult actionResult = Invoke(() => new SomeController().Index()); var RestultViewModel = ModelFromActionResult>(actionResult); Very happy with this test now. – Patrik Lindström Jan 06 '13 at 16:52
  • If you would like to find more improvements based on the same techniques please refer to my newly github project which combines yet more features in an easy to use way. http://www.codeproject.com/Tips/850277/ASP-NET-MVC-End-to-End-Integration-Testing – Ibrahim ben Salah Dec 31 '14 at 12:34
12

consider a = ActionResult;

ViewResult p = (ViewResult)a;
p.ViewData.Model
Omu
  • 69,856
  • 92
  • 277
  • 407
2

It's somewhat cheating but a very trivial way to do so in .NET4

dynamic result = controller.Action(123);

result.Model

Used this today in a unit test. Might be worth some sanity checks such as:

Assert.IsType<ViewResult>(result); 
Assert.IsType<MyModel>(result.Model);

Assert.Equal(123, result.Model.Id);

You could skip the first one if the result is going to be a view or partial result depending on the input.

Chris Marisic
  • 32,487
  • 24
  • 164
  • 258