|
When you create a new ASP.NET MVC project, one of the first things that you might notice is that you get an AccountController which takes advantage of the ASP.NET membership provider to allow your site to automatically do forms-based authentication right from the very beginning. This is a very handy feature and definitely helps get you going quickly.
The issue is that when you look at the unit tests for the AccountController, they are positively littered with manually mocked classes. I realize that this is because you don't want to make the default project template rely on a third party mocking library so in this blog post, I'm going to show how you can delete all of the manually implemented mocks for the identity, principal, membership service and forms auth service. The secret is using Moq. Moq is a lightweight mocking framework for .NET that was designed specifically for the .NET Framework 3.5 and LINQ. As such, definining mock expectations and mock return values is all done through lambdas in a ridiculously easy to read syntax, as you'll see below.
First, you want to add a reference to the Moq library. To get Moq, you can go to Moq's Google Code home page . Once you've got the Moq library on your machine, add a reference to it from your unit test project (you did choose to create a unit test project with your new ASP.NET MVC project, didn't you?). With that in place, you can replace the contents of the "GetAccountController()" method with the Moq-enabled one below:
private static AccountController GetAccountController()
{
var mockFormsAuth = new Mock<IFormsAuthentication>();
var mockUser = new Mock<MembershipUser>();
mockUser.Setup(u => u.ChangePassword(It.IsAny<string>(),
It.Is<string>(s => s == "newPass"))).Returns(true);
var mockMembership = new Mock<MembershipProvider>();
mockMembership.Setup(m => m.EnablePasswordReset).Returns(false);
mockMembership.Setup(m => m.EnablePasswordRetrieval).Returns(false);
mockMembership.Setup(m => m.MinRequiredNonAlphanumericCharacters).Returns(0);
mockMembership.Setup(m => m.MinRequiredPasswordLength).Returns(6);
mockMembership.Setup(m => m.ValidateUser(It.IsAny<string>(),
It.Is<string>(s => s == "goodPass"))).Returns(true);
mockMembership.Setup(m => m.GetUser(It.IsAny<string>(),
It.IsAny<bool>())).Returns(mockUser.Object);
// Registration success mock
MembershipCreateStatus goodStatus = MembershipCreateStatus.Success;
mockMembership.Setup(m => m.CreateUser(It.Is<string>(s => s == "someUser"),
It.Is<string>(s => s == "goodPass"),
It.Is<String>(s => s == "email"), It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<bool>(),
It.IsAny<object>(),
out goodStatus)).Returns(mockUser.Object);
// Registration failed mock (duplicate username)
MembershipCreateStatus dupeStatus = MembershipCreateStatus.DuplicateUserName;
mockMembership.Setup(m => m.CreateUser(It.Is<string>(s => s == "someUser"),
It.Is<string>(s => s == "badPass"),
It.Is<string>(s => s == "DuplicateUserName"),
It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<object>(), out dupeStatus));
AccountMembershipService mockService =
new AccountMembershipService(mockMembership.Object);
AccountController controller = new AccountController(mockFormsAuth.Object, mockService);
controller.SetFakeAuthenticatedControllerContext();
return controller;
}
What you can then do is delete all of the manually created Mock classes. Additionally, there's a unit test that verifies whether or not the constructor has set the appropriate properties. You can remove that if you're using Unity to construct your objects (which I am, as indicated in the previous blog post).
The SetFakeAuthenticatedControllerContext() is an adaptation from one of Scott Hanselman's MvcMockHelpers.
What I like so much about this is that Moq lets me take the intent of the original code and reduce all that extra plumbing and "ceremony" and just get down to what is really important - what I want the Moq objects to provide to my objects under test. I can't imagine doing unit testing without a decent mock framework like this and again, what I like about Moq is its simplicity.
oh,I am sorry commt here... I am fans of you, I read your book recently. I
am reading << ASP.NET E-Commerce Programming: Problem - Design -
Solution>> and it helpful to my project. but I can't find the source
code of this book on network. so, I find your blog hoping could get the
source code . I am sorry again for my english. If you can find the code
email to xyingjie@gmail.com please, thanks!
This is very informative and helpful