In this post, i will start with an MVC sample created from the default template project that is bundled with ASPNET MVC2 installation. This template provides not just a dummy project with folder organized but rather a full running app.The target of this post is to show a mocking of a controller action, in that regard i have picked registration action chosen from the accounts controller of the provided sample that looks similar to:
- [HttpPost]
- public ActionResult Register(RegisterModel model)
- {
- if (ModelState.IsValid)
- {
- // Attempt to register the user
- MembershipCreateStatus createStatus = MembershipService.CreateUser(model.UserName, model.Password, model.Email);
-
- if (createStatus == MembershipCreateStatus.Success)
- {
- FormsService.SignIn(model.UserName, false /* createPersistentCookie */);
- return RedirectToAction("Index", "Home");
- }
- else
- {
- ModelState.AddModelError("", AccountValidation.ErrorCodeToString(createStatus));
- }
- }
-
- // If we got this far, something failed, redisplay form
- ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
- return View(model);
- }
Here the basic workflow that can be ensured for the target action are:
- For valid status:
- Creates the user with membership service.
- Validates the create status.
- On validating , signs in the user.
- Returns to expected action.
- For Invalid status:
- Stores the password length.
- Return;
Accordingly, to cover the first criteria that covers a valid registration. We first created the accounts controller and the registration model.
- AccountController controller = new AccountController();
- RegisterModel registerModel = new RegisterModel();
In order to validate model state, we also need to mock out the ModelStateDictionary to set our expectation:
- var modelState = Mock.Create<ModelStateDictionary>();
Then, according to flow, we setup:
- Mock.Arrange(() => modelState.IsValid).Returns(true).MustBeCalled();
- Mock.Arrange(() => controller.ModelState).Returns(modelState);
Next, we need to pass out our custom MembershipService to the controller and set it to return a valid response ignoring the arguments. We are ignoring the arguments, as here the specific argument is not important and we are concerned more with the desired step that should be completed.
- // mock membership service
- var membershipService = Mock.Create<IMembershipService>();
- Mock.Arrange(() => membershipService.CreateUser("", "", "")).IgnoreArguments()
- .Returns(MembershipCreateStatus.Success).MustBeCalled();
- controller.MembershipService = membershipService;
Now, after having a successful registration our next goal is to make sure that developer has written the sign in code correctly and accordingly we do:
- // mock auth services
- var formsAuthService = Mock.Create<IFormsAuthenticationService>();
- Mock.Arrange(() => formsAuthService.SignIn("", false)).IgnoreArguments().MustBeCalled();
- controller.FormsService = formsAuthService;
To wrap it up and give a test run, we execute the controller with the RegisterModel object that we have created previously.
- // act
- controller.Register(registerModel);
Finally, we make sure that required calls are made properly.
- // assert
- Mock.Assert(modelState);
- Mock.Assert(membershipService);
- Mock.Assert(formsAuthService);
Now, this is of a rough test, as you can see there are three different types of assert which should spun three different test methods. I left that to the reader :-).
P.S. This example is done using JustMock , by the time of writing this post IgnoreArguments() is still under its way to release[Justmock still in its beta]. The way shown for ignoring arguments can also be done using matcher, but it is to mention that for two or many arguments when we just want to ignore the whole chunk, using a modifier call is more elegant and cleaner to read.
Previously, i made a post showing how you can leverage the dependent interfaces that is implemented by JustMock during the creation of mock instance. It could be a informative post that let you understand how JustMock behaves internally for classes or interfaces implement other interfaces into it. But the question remains, how you can add your own custom interface to your target mock. In this post, i am going to show you just that.
Today, i will not start with a dummy class as usual rather i will use two most common interfaces in the .NET framework and create a mock combining them. Before, i start i would like to point out that in the most recent release of JustMock we have extended the Mock.Create<T>(..) with support for additional settings though closure. You can add your own custom interfaces , specify directly the real constructor that should be called or even set the behavior of your mock.
Doing a fast forward directly to the point, here goes the test code for create a creating a mock that contains the mix for ICloneable and IDisposable using the above mentioned changeset.
- var myMock = Mock.Create<IDisposable>(x => x.Implements<ICloneable>());
- var myMockAsClonable = myMock as ICloneable;
- bool isCloned = false;
-
- Mock.Arrange(() => myMockAsClonable.Clone()).DoInstead(() => isCloned = true);
-
- myMockAsClonable.Clone();
-
- Assert.True(isCloned);
Here, we are creating the target mock for IDisposable and also implementing ICloneable. Finally, using the “as” to get the ICloneable reference then did the usual like arranging it, acting on it and assert if the expectation is met properly.
Similarly, you can do the same for a given class:
- var realItem = Mock.Create<RealItem>(x =>
- {
- x.Implements<IDisposable>();
- x.CallConstructor(() => new RealItem(0));
- });
- var iDispose = realItem as IDisposable;
-
- iDispose.Dispose();
You can implement as many as interfaces you want. Here in this rudimentary example, i am also calling the real constructor for a given RealItem class. This is to mention that you can implement custom interfaces only for non-sealed classes in conjunction with interfaces or less it will end up with an exception (proper). Also, this feature don’t require any profiler, if you are an agile developer or running it inside silverlight runtime feel free to try it turning off the JM add-in :-).
TIP : Ability to specify real constructor could be an useful productivity boost in cases for code change where you can re-factor the usage just by one click with your favorite re-factor tool.
That’s it for now. Here goes the link from previous post:
http://weblogs.asp.net/mehfuzh/archive/2010/04/26/working-with-multiple-interfaces-on-a-single-mock.aspx
Enjoy!!