test controller method + DataAnnotations - asp.net mvc 3 - asp.net

This is a follow up on this:
other SO post
Is this a good way to test whether the validation based on DataAnnotations works in the controller:
[Test]
public void UserController_CannotCreateUserWithNoLastName()
{
// Arrange
var user = new CreateUserViewModel();
UsersController controller = new UsersController();
var validationContext = new ValidationContext(user, null, null);
var validationResults = new System.Collections.Generic.List<ValidationResult>();
Validator.TryValidateObject(user, validationContext, validationResults);
foreach (var validationResult in validationResults)
{
controller.ModelState.AddModelError("", validationResult.ErrorMessage);
}
// Act
var result = controller.CreateUser(user);
// Assert
Assert.IsFalse(controller.ModelState.IsValid);
}
Any improvement suggestions would be very much welcome. I am also wondering whether one usually writes one test for each validation/business rule. Thanks!

Is the code you listed based off of what's found here?
Personally, I write tests like so on a per annotation basis:
[Test]
public void CreateEventViewModel_Description_Property_Contains_StringLength_Attribute()
{
// Arrange
PropertyInfo propertyInfo = typeof(CreateEventViewModel)
.GetProperty("Description");
// Act
StringLengthAttribute attribute = propertyInfo
.GetCustomAttributes(typeof(StringLengthAttribute), true)
.Cast<StringLengthAttribute>()
.FirstOrDefault();
// Assert
Assert.NotNull(attribute);
Assert.AreEqual(255, attribute.MaximumLength);
}
I based this off of some information that Brad Wilson posted some time back. These tests are stored separate of the controller tests. I'm not sure if there's a more efficient way of doing this today (some folks have created more generic helper methods to do this type of testing; I just prefer having explicit tests for each attribute on my own) but it will verify that your data annotations do exist on your view models as expected.
A combination of this type of test, specifically verifying attributes, along with tests to test model state as listed in your previous question
UsersController.ModelState.AddModelError("username", "Bad username");
is what I typically go with.

Related

AutoFixture - customization using ISpecimenBuilder derived class - issues with casting request to PropertyInfo

I am using AutoFixture 4.17 in .NET 6
I am trying to create my own customization generator for DateTime
I read several tutorials and my code base on them.
It was said, that request parameter to Create method should be of type PropertyInfo so we can further analyze it. However, it is of type SeededRequest having inside Request property of anonymous type.
What is the best way now to analyze this Request field? Can I cast it somehow? To what type?
UPDATE:
I found a solution by casting it to dynamic type:
dynamic dyn = request as dynamic;
dynamic req = dyn.Request as dynamic;
if(req.Name != "DateTime")
but I'm not sure if this is the best approach.
You might want to learn more about reflection and pattern matching in .NET.
AutoFixture uses reflection a lot to be able to generate test data.
Here's a sample that might help you get started.
[Fact]
public void Foo()
{
var fixture = new Fixture();
fixture.Customizations.Add(new MyDateTimeGenerator());
var time = fixture.Create<DateTime>();
Assert.Equal(new DateTime(2011, 12, 13), time);
}
public class MyDateTimeGenerator : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var isDateTimeRequest = request is Type type
&& type == typeof(DateTime);
if (!isDateTimeRequest)
return new NoSpecimen();
return new DateTime(2011, 12, 13);
}
}

Unit testing if methods find and return a view in ASP.NET

I'm new to ASP.NET and I'm refactoring some functionalities in my MVC-structured ASP.NET application into area's. This has already lead to controller-methods not able to find their views anymore, which results in the following page:
To test if all controllers can find their views, I'd like to write some automated unit tests for this.
I have came up with the following:
[TestMethod]
public void AboutTest()
{
var controller = new HomeController();
var result = controller.About() as ViewResult;
Assert.IsNotNull(result);
}
which tests the About-method in the following code:
public class HomeController : Controller
{
public ActionResult About()
{
return View();
}
public ActionResult Contact()
{
return View("~/Views/SomeFolder/Contact.cshtml");
}
}
But even when the HomeControllers About-method can not find a view, this assert succeeds, so this does not work for me.
I have found a solution online to use use ViewEngine.FindView() here. I don't think I can use this, since in some controllers the views are referenced by a hardcoded string (see the contact method in the example controller above) instead of just returning the default view (simularly named as its method). The ViewEngine.FindView(controller.ControllerContext, "about", "about"); will then fail, but the controller-method would not.
Another solution states to use Assert.IsEqual() and check if the result.ViewName is equal to a hardcoded string (for example: "About"). Since I do not set or know the title of the views I'm expecting to get returned, this would not be a solution either.
(How) would I be able to test my application for this?
You shouldn't check for null, it will return a ViewResult even when it doesn't render.
To test whether it actually renders use AssertViewRendered from mvccontrib.
[TestMethod]
public void AboutTest()
{
var controller = new HomeController();
var result = controller.About().AssertViewRendered();
}
You can even check for a specific view like so:
result.AssertViewRendered().ForView(MVC.Your.Views.AboutView);
Or supply data like so:
controller.page().AssertViewRendered().ForView("page").WithViewData<SomeModel>();
For an interactive tutorial with lots of pictures I can recommend: http://toreaurstad.blogspot.nl/2011/09/adventures-with-mvccontrib-testhelper.html
Edit:
You might also check out Selenium to test your entire app (incl. rendering of 200 routes).

Testing Repository update or insert using Moq

I have a method like this:
public int InsertOrUpdateCustomer(Customer customer)
{
var result = default(int);
try
{
using (var customerContext = new Customer())
{
var customerResult = customerContext.UpdateGraph(coupon, map => map.OwnedCollection(p => p.CustomerPoints));
couponsContext.SaveChanges();
result = customerResult.CustomerTypeID;
}
}
catch (Exception ex)
{
// Log the Exception
}
return result;
}
It creates an instance of CustomerContext, Saves, and returns the new CustomerID.
I am trying to use Moq for this and have this method where the test needs to check for a integer value being returned.
[TestMethod]
public void Inserting_A_Customer_Should_Return_A_IntegerValue(Customer customer)
{
var mock = new Mock<ICustomerRepository>();
int customerId = 1;
mock.Setup(c => c.InsertOrUpdateCustomer(customer)).Returns(new Customer() { Id = customerId });
}
That gives this error:
cannot convert from 'Entities.Commerce.Customer' to 'System.Func<int>'
I am also new to Moq.
What I would like to know from this question is, if one has a code like above, how does one proceed with writing Unit Tests.
It would be of great help if some pointers are given in getting to know that process.
Thanks in advance.
The error itself is because the method you are setting up is of this signature:
public int InsertOrUpdateCustomer(Customer customer)
Whereas your setup is trying to return a customer
mock.Setup(c => c.InsertOrUpdateCustomer(customer))
.Returns(new Customer() { Id = customerId });
Changing this to return a fake int such as .Returns(42); will avoid the error.
The not so good news is if the purpose of the test is Inserting_A_Customer_Should_Return_A_IntegerValue that you will be mocking the very thing you are trying to test (you would just be testing Moq).
What you need to do is Moq out your DbContext, which makes this line problematic, given its tight coupling:
using (var customerContext = new CustomerContext())
The suggestion here is to either allow the DbContext to be injected into the constructor of your class you are testing (or inject a factory interface which can create a DbContext).
You can then Mock the DbContext and the relevant IDbSets (Customers) as per this MSDN article here, which you can then inject into your class being tested, and test any logic / branching in your class.

Unit test controller that uses application scoped variables

I'm building an ASP.NET MVC4 app. I'm not using any mocking framework and, if possible, would prefer not to at this point. My question is 2 parts.
I have a controller that uses a variable created in Global.asax. In the controller I access the variable like this.
HttpContext.Application["MyVar"]
1) Is this a best-practice for application wide variable usage? If not, what's the best way?
In an attempt to unit test this controller I added the following code (from here) to my test method.
MyController target = new MyController();
var request = new HttpRequest("", "http://example.com/", "");
var response = new HttpResponse(System.IO.TextWriter.Null);
var httpContext = new HttpContextWrapper(new HttpContext(request, response));
target.ControllerContext = new ControllerContext(httpContext, new RouteData(), target);
target.ControllerContext.HttpContext.Application["MyVar"] = new MyVar();
The problem is I can't add anything to Application. The last line of code doesn't seem to do anything and the collection remains empty. I've also tried this in VS's Immediate Window without success.
2) In the unit test, how can I add the application level variables the controller needs?
In general globals aren't good for testing. There are at least two approaches you could take.
Use a mocking framework like Pex/Moles, NMock, etc.
Use an inversion-of-control approach (NInject is my favorite). If class like a controller has an external dependency, it asks for the interface, typically in its constructor.
private readonly IApplicationSettings _settings;
public MyController(IApplicationSettings settings)
{
_settings = settings;
}
void someMethod()
{
_settings.Get("MyVar");
}
This way you can write real and test implementations.
public LiveAppSettings : IApplicationSettings
{
public string Get(string key)
{
return HttpContext.Current.Application[key];
}
}
With Ninject, you can bind either implementation at application startup:
var kernel = new StandardKernel();
kernel.Bind<IApplicationSettings>().To<LiveAppSettings>();
Is this a best-practice for application wide variable usage?
Best practice is a bit of a subjective notion and without fully explaining your scenario and what precisely are you trying to achieve I prefer not to discuss it.
We cannot discuss whether this is best practice but from what I can see it is not wrong either. It is not wrong because you are using the abstractions allowing the code to be unit tested.
In the unit test, how can I add the application level variables the controller needs?
You could use a mocking framework such as Rhino Mocks to mock the abstractions that the controller needs. Let's take as an example the following controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var myVar = (MyVar)HttpContext.Application["MyVar"];
return Content(myVar.Foo);
}
}
and we would like to unit test the Index action. Here's a sample unit test:
[TestMethod]
public void Index_Action_Should_Retrieve_MyVal_From_AppState()
{
// arrange
var target = new HomeController();
var httpContext = MockRepository.GeneratePartialMock<HttpContextBase>();
var application = MockRepository.GeneratePartialMock<HttpApplicationStateBase>();
application.Expect(x => x["MyVar"]).Return(new MyVar { Foo = "bar" });
httpContext.Expect(x => x.Application).Return(application);
target.ControllerContext = new ControllerContext(httpContext, new RouteData(), target);
// act
var actual = target.Index() as ContentResult;
// assert
Assert.AreEqual("bar", actual.Content);
}

Proper way of using FormCollection in ASP.NET MVC2 Create Method?

I am currently developing an application with the new ASP.NET MVC2 framework. Originally I started writing this application in the ASP.NET MVC1 and I'm basically just updating it to MVC2.
My problem here is, that I don't really get the concept of the FormCollection object vs. the old Typed object.
This is my current code:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
try
{
Member member = new Member();
member.FirstName = collection["FirstName"];
member.LastName = collection["LastName"];
member.Address = collection["Address"];
// ...
return RedirectToAction("Details", new { id = member.id });
}
catch
{
return View("Error");
}
}
This is the Code from the MVC1 application:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Member member)
{
try
{
memberRepository.Add(member);
memberRepository.Save();
return RedirectToAction("Details", new { id = member.id });
}
catch
{
}
return View(new MemberFormViewModel(member, memberRepository));
}
What are the benefits of switching to FormCollection in MVC2 and more importantly - how is it used properly?
You had the FormCollection object in v1 as well. But it is more preferred to use a typed object. So if you are already doing that, then continue doing so.
By using FormCollection, you wind up manually matching your post data or query string key/values into values to use in your code using string typing (resulting in stringly-typed code), when instead the built-in Model Binding can do this for you if you use form models, aka "typed objects."
I think by using the FormCollection, you would probably also lose the ability to use the handy Data Annotation (slash Validation) attributes on your model objects as well, which are designed for use with typed object model binding.
Additionally, unit testing can become much more cumbersome once you start touching your controller.Request.Form. You might find yourself having to mock and setup an HttpContextBase, and an HttpRequestBase just to have that mock request's .Form property return the NameValueCollection that you are wanting your test to see. Contrast this to letting model binding do the work for you such as:
// Arrange
var myModel = new MyModel( Property1 = "value1", Property2 = "value2");
// Act
var myResult = myController.MyActionMethod(myModel);
// Assert
// whatever you want the outcome to be
In summary, I would recommend against using FormCollection to the maximum extent possible.

Resources