Recently I have started playing with the Moq (pronounced "Mock-you" or just "Mock") a Mocking Library for .NET Developers, that takes full advantage of .NET 3.5 (i.e. Linq expression trees) and C# 3.0 features. Here in this post I will discuss how I have used the TryUpdateModel method in the Form POST scenario and also share how I have written a test case using Moq mocking library to deal with the TryUpdateModel<TModel>(TModel model) method of the ASP.NET MVC controller.
I have a very simple user interface, that allows user to enter data and submit, to add a new "User".
My View Page is:
and my "Action" is
You may have already noticed that I have decorated my action without any parameters, and my POST related codes are executed by checking the request type.
if (Request.RequestType == POST)
{
//code
}
As I have no parameters in my CreateUser(), I did not need to create separate action with AcceptVerbs("GET") and AcceptVert("POST") attribute. I have created an empty instance of MembershipCreateViewModel object and passed it to the TryUpdateModel() method to get the values of the posted form into my viewmodel object. MVC framework takes care of the rest and populates the viewModel with the desired values. Also note the RedirectToAction() method has been on success, it is very important to perform this client - redirect. It will ensure that the form does not resubmit, and the user will never see a prompt like this, if he hits the browser refresh button.
My MembershipCreateViewModel class is as follows,
I did not prefer passing four parameters to my CreateUser() Action such as,
[AcceptVerbs["POST"])
CreateUser(string username, string email, string password, string confirmPassword)
{
//code
}
instead I kept the method simple by using the MembershipCreateUserViewModel to communicated between the Controller and the View.
This is all good, but by now you may be wondering how would I test this Controller>Action. Lets explore that part. Here I will demonstrate my TestCase using the Moq framework, but you can do the same using other popular mocking frameworks like Rhino Mock, NMock, NMock2, NUnit.Mocks, EasyMock, TypeMock etc, or even with plain vanilla C# code. First of all I will need a FakeHttpContext to interact with my Controller from the test environment.
It is very straight forward to create a mock of a class or interface in Moq, I have created mocks of HttpContextBase, HttpRequestBase, HttpResponseBase, HttpSessionStateBase, HttpServerUtility above and decorated methods and properties that I use in my test cases using the Setup and SetupGet method that is available in the Moq library.
Note how easily with couple of lines of code I have a mockup of the HttpContextBase. The Mock<T> allows creation of custom value matchers that can be used on setups and verification, completely replacing the built-in It class with our own argument matching rules.
var httpContext = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>
httpContext.Setup(ctx => ctx.Request(request.Object);
This above code snippet is creating mock instances of HttpContexBase and HttpRequestBase classes, and then also setting up that httpContext.Request will return the mock instance "request".
Now lets look at how I have used this mock httpContext in a test case.
I have created a test case here that tests our CreateUser() action. Note I have created an instance of the ControllerContext and passed the httpContext mock object as a parameter of its constructor. After that I have assigned this instance ( context ) to the controller.ControllerContext property.
The Mock.Get() method is interesting it can retrieve a mock object for the given object instance. Here I have retrieved the request object and have modified it further. I have setup so that the request.Form returns NameValueCollection. You may be wondering why did I pass NamValueCollection. You may recall that I have used the TryUpdateModel() method in my action to get the form values into our viewmodel, and if you look what is happening under the hood of TryUpdateModel() method you will find that, "Form" is of type System.Collections.Specialized.NameValueCollection and a member of System.Web.HttpRequestBase, and
the internals of TryUpdateModel() iterates through each item of the ContollerContext.HttpContext.Request.Form object and populates the matching properties of the viewmodel using reflection. The above code snippet from the ValueProviderDictionary class where we see that the keys are being read from the Form object to populate a dictionary.
Conclusion
Here in this post I have discussed a Form POST scenario and I have decorated my action method without any parameters as by default TryUpdateModel method looks at the submitted Form object and attempt to assign it to the viewmodel object that we pass. I have also demonstrated how I have used the Moq library to create fake/mock objects for my testcases, how I have setup some fake methods and properties. I have also demonstrated the handy Mock.Get method that can retrieve a mock object from a given object instance and allows us to modify the mock object further. Thank you for being with me so far and I hope this helps.