MVC3 unit testing - asp.net

Im new to mvc 3 and I'm doing unit tests. I'm testing a search action method. This method returns an action method that contains a generic list of some type. How do I test if the model data returned is of that specified type?
Please help.

In your test method you do a type assertion after you have obtained the search results in a variable. Here is an assert for NUnit:
var searchResults = SearcherUnderTest.Search("TestKeyword");
Assert.IsInstanceOfType( Type expected, object searchResults );

Do you mean that you want to test the type of T in a List? If so then look at this question: How to get the type of T from a member of a generic class or method?
Or do you need help with writing a unit test for an action? Then: How to unit test an ActionResult that returns a ContentResult?
Testing with Nunit, it usually looks like this when testing search results:
[Test]
public void Search_ShouldReturnAListOfOrders()
{
var result = _controller.Search("searchParameter") as MyViewModel ;
Assert.That(result, Is.Not.Null);
Assert.That(result.SearchResults, Is.Not.Null);
Assert.That(result.SearchResults.Count, Is.GreaterThan(0));
}

Related

Moq.MockVerificationException not public xUnit Assert.Throws

I am testing a method which will call another method if certain parameters are certain values and not if they are other.
I was using Moq's Verify to test this. However when I use the xUnit to see if the method is not called when sending parameters with data which should not make the method call the 2nd method.
Problem is that I cannot do
mockObject.Verify();
Assert.Throws<Moq.MockVerificationException>(()=>mockObject.Method());
I changed from MSTest to xUnit because the support for throws was built in and I had to have the ExpectedException attribute decorating my test method before.
I tried to cast the Moq non-public exception to the public parent Moq.MoqException but that will throw an error.
so I think I may have to do:
try {moqObj.Verify();}
catch(Moq.Exception mve)
{
Assert.SomethingIsException();
}
As I understand, you're just trying to verify whether certain methods are called or not? If so, try this:
var theThing = new Mock<IThing> ();
theThing.Verify (x => x.DoSomething ("a"), Times.Never);
theThing.Verify (x => x.DoSomething ("b"), Times.Once);
If you need to invoke another method after the first method is called, you could use a callback:
theThing.Setup (x => x.DoSomething ("a")).Callback (() => {});

Why is it that when I pass a Model to my .Net MVC 4 Controller Action it insists on using it in the Partial Update?

I am intending to pass a Hotel model to my Controller Action - Do some checks/processing on it, then return a potentially different Hotel model rendered in a Partial View.
The problem I'm getting is that if I pass the oHotelParameter Model to the Action then the PartialView uses the model passed to the Action instead of the one passed to the PartialView method.
If I remove the oHotelParameter Parameter from the Action then the View is Rendered as expected using oHotel.
public ActionResult _SaveMasterDetails(Hotel oHotelParameter)
{
//Do some processing on oHotelParameter
//........
Hotel oHotel = new Hotel();
oHotel.GetHotelInfoById(14); //This gets a different Hotel object just for a test
//For some reason oHotel is ignored and oHotelParameter is used instead unless I remove oHotelParameter
return PartialView("_MasterDetails", oHotel);
}
When I debug the View I see that the Model is set to the value I pass to PartialView (oHotel), yet the result I see coming back from the Action contains data from the oHotelParameter object.
In case it makes a difference, I am calling the Action from jQuery ajax.
Can anyone explain why this should happen?
when mvc handles a form post, it fills the ModelState object with the details of the model.
This is when used when the view is rendered again from the post action, this is incase you have thrown the view back out because it has failed validation.
If you want to pass out a new model and not use the view state, then you can call ModelState.Clear() before returning the view and that should let you rebind the view to the new model.
I think that it would help if you had a better understanding of how model binding works when you post back to an action method. In most cases, it is unecessary and inefficient to pass a view model as a parameter to a POST action method. What you are doing is loading the view model into memory twice when you pass your view model as a parameter (assuming a strongly typed view). When you do a post back the model becomes part of the form collection (through model binding) in the request object in the BaseController class that every controller inherits from. All that you need to do is to extract the model from the Form collection in the Request object in the BaseController. It just so happens that there is a handy method, TryUpdateModel to help you do this. Here is how you do it
[POST]
public ActionResult Save()
{
var saveVm = new SaveViewModel();
// TryUpdateModel automatically populates your ViewModel!
// TryUpdateModel also calls ModelState.IsValid and returns
// true if your model is valid (validation attributes etc.)
if (TryUpdateModel(saveVm)
{
// do some work
int id = 1;
var anotherSaveVm = GetSaveVmBySomeId(id);
// do more work with saveVm and anotherSaveVm
// clear the existing model
ModelState.Clear();
return View(anotherSaveVm);
}
// return origonal view model so that the user can correct their errors
return View(saveVm);
}
I think that the data in the form collection contained in the request object is being returned with the view. When you pass the model back to the post action method as a parameter, I believe it is passed in the query string (see Request.QueryString). Most of the time, it is best to only pass one or two primitive type parameters or primitive reverence types such as int? to an action method. There is no need to pass the entire model as it is already contained in the Form collection of the Request object. If you wish to examine the QueryString, seee Request.QueryString.

PHPUnit and Call-time pass-by-reference

I have a unit test that I am writing and have run into an annoying problem... Let's say I have the following function I am testing:
public function functionToTest(array &$data, parameter2)
{
// perform some action on the array that is being passed in by reference
}
Now, when I attempt to call this function in my unit test, I would do something like this:
public function testMyFunction()
{
$data = array('key1' => 'val1');
$mockOfClass = $this->getMockBuilder('ClassName')
->disableOriginalConstructor()
->setMethods(array('method1', 'method2')) // My function to test is NOT in this list
->getMock();
$this->mockOfClass->functionToTest($data, true);
// Perform assertions here
}
However, I receive the following error message:
Parameter 1 to ClassName::addNewFriendsToProfile() expected to be a reference, value given
This seemed very strange to me. First of all, I'm just passing an array by reference, so it it shouldn't have a problem with this. Secondly, Why parameter 1? Doesn't it mean parameter 0? Then, I tried changing the call to the following:
$this->mockOfClass->functionToTest(&$data, true);
After making this change, it works fine. Unfortunately, it also produces the following warning:
Call-time pass-by-reference has been deprecated in /PathToFile on line xxx
I do not encounter this error when running the actual code. It only throws this error in the unit test. Also, I need to use the mock as there are methods in the class I am mocking; So I can't simply create a new instance of the class and call the method that is being tested. Is there any way I can get around this?
It turns out that PHPUnit clones each of the parameters that are being passed in (Thanks Tim Lytle for pointing me to this source: Pass by reference in a callback when mocking in PHPUnit). This is what causes the error if the array is passed in without a reference at call-time in the unit test. Luckily, the solution is simple. Instead of passing the array by reference, I pass in the array by value and return the array.
before:
public function someFunction(array &$myArray)
{
$myArray[] = 'new val';
}
after:
public function someFunction(array $myArray)
{
$myArray[] = 'new val';
return $myArray;
}

Testing results with Massive

I'm returning a list to my MVC controller from Massive. When I'm in my test how can I check that there are 3 records (as expected) in the returned list?
My test code currently returns the 3 records from a call and populates into my ViewModel (model) but when I try to run .Count() it's saying object has no Count method. Since it's a dynamic type what do I do?
My test code:
var result = _controller.Index() as ViewResult;
var model = result.Model as MyExperienceListModel;
Assert.AreEqual(3, model.Experience.Count());
model.Experience is dynamic btw.
I got this working by having my returned result set from my Massive class as a IEnumerable<dynamic> in my ViewModel. So:
MyExperienceListModel{
public IEnumerable<dynamic> Experience { get; set;}
}
Hope it helps someone else out.

Unit Test for a View Attribute using Moq

I am using Moq for unit testing and I would like to test for a view's attribute.
In this case the Authorize attribute.
Example View Code:
[Authorize(Roles = "UserAdmin")]
public virtual ActionResult AddUser()
{
// view logic here
return View();
}
So I would like to test the view attribute when I act on this view with a user that is in the role of UserAdmin and a user that is not in the role of user admin. Is there anyway to do this ?
Example Test:
[Test]
public void Index_IsInRole_Customer()
{
// Arrange
UserAdminController controller = _controller;
rolesService.Setup(r => r.IsUserInRole(It.IsAny<string>(), It.IsAny<string>())).Returns(false); // return false for any role
// Act
var result = controller.AddUser();
// Assert
Assert.IsNotNull(result, "Result is null");
}
Attributes are just metadata on the type, so they don't do anything unless the surrounding infrastructure make them do something (or better yet: the surrounding infrastructure does something based on the information in those attributes). That's what the ASP.NET MVC framework does when it executes a request.
That is not what you do when you create and invoke a Controller Action in a unit test, so unless you want to go to great lengths to invoke the Controller Action using a ControllerActionInvoker (at which point the test ceases to be a unit test and becomes an integration test) you can't directly test the behavior implied by the attribute.
You can, however, write a unit test that verifies that the attribute correctly decorates the Controller Action:
var attributes = typeof(UserAdminController)
.GetMethod("AddUser").GetCustomAttributes(true);
var result = attributes.OfType<AuthorizeAttribute>().Single();
Assert.AreEqual("UserAdmin", result.Roles);
When executing the test above the AuthorizeAttribute will not be taken into account (that is, no one will evaluate it). This is normally the responsibility of the ControllerActionInvoker (a class in System.Web.Mvc).
You might want to just trust that AuthorizeAttribute is correctly implemented. Then just use reflection to verify that the AuthorizeAttribute has been correctly defined on your action.

Resources