My previous two posts introduced WebformsMVP (part 1, part 2), in order to get a separtion of markup and logic in ASP.NET applications. This post will give an introduction to using the WebformsMVP in a real world scenario on a CMS called Sitecore.
What you need:
- Sitecore (I tested with Sitecore 6.0.0 rev 090120, but any Sitecore installation could be used)
- Visual Studio 2010
- Moles from RiSE
- Rhino Mocks (I use 3.6)
Introduction to Moles
Research in Software Engineering (RiSE) at Microsoft Research have created two projects, Pex and Moles. It allows for Isolation and White box Unit Testing for .NET, where Pex automatically generates test suites with high code coverage and Moles allows to replace any .NET method with a delegate. (Moles is free, but Pex is not, use MSDN subscription or other to obtain).
The following video demonstrates a simple example using Moles: Moles - Replace any .NET method with a delegate. However, the video is a bit old, but the directions below should be updated
.
The project
For a new project we received, I had to create a way to change the admin password, since the customer was not aware of its value. So this simple project is going to create a control to reset the admin password and we are going to test it..
The project structure:
- Website
- Website.Logic
- Website.Logic.Tests
Taken from the model provided by WebformsMVP.
Our project consists of a UserControl which displays the new password, a presenter which changes the password and a test class for testing the presenter.
The UserControl uses a simple model:
1: public class ChangePassword
2: {
3: public string Password { get; set; }
4: }
The markup is also pretty simple:
1: New password: <%= this.Model.Password %>
The presenter attaches to the View.Load event and releases in ReleaseView, but I won’t show that here. The View_Load event listener is displayed below:
1: var password = "No success";
2: var domain = Sitecore.Security.Domains.Domain.GetDomain("sitecore");
3: if (domain != null)
4: {
5: var userQuery = from u in domain.GetAccounts()
6: where u.Name.Equals("sitecore\\admin", StringComparison.CurrentCultureIgnoreCase)
7: select u;
8: var user = userQuery.FirstOrDefault();
9: if (user != null)
10: {
11: var mUser = Membership.GetUser(user.Name);
12: if (mUser != null)
13: {
14: try
15: {
16: password = mUser.ResetPassword();
17: }
18: catch (Exception)
19: {
20: // Missing logging
21: }
22: }
23: }
24: }
25: View.Model = new ChangePassword { Password = password };
The above code is pretty straightforward, but the testing could be rather complex. First of we have an issue with mocking the static method GetDomain from the Domain class. However Moles saves us from a lot of pain!
Add a reference to the logic class library, to Rhino.Mocks, WebformsMVP and Microsoft.Moles.Framework in the test project and add a reference to Sitecore.Kernal from the /bin folder of the Sitecore website.
Having installed Moles, you get an option to “mock” an assembly via Visual Studio. Right click on the Sitecore.Kernel assembly reference in the test project and select “Add Moles Assembly”:

This will add a file to your project called “Sitecore.Kernel.moles” and when you build (Takes a long time the first time), Moles create an extra assembly called Sitecore.Kernal.Moles:

Now we are ready to create our first test method:
1: [TestMethod]
2: [HostType("Moles")]
3: public void ViewLoadNoAdminAccountFound()
4: {
5: // Arrange
6: var expectedPassword = "No success";
7: var view = MockRepository.GenerateStub<IView<ChangePassword>>();
8: var presenter = new ResetAdminPasswordPresenter(view);
9: var accounts = new List<Account>();
10:
11: // Redirect Domain.GetDomain to our delegate
12: MDomain.GetDomainString = (s) =>
13: {
14: var dom = MockRepository.GenerateMock<Domain>(s);
15: dom.Stub(d => d.GetAccounts()).Return(accounts.AsEnumerable());
16: return dom;
17: };
18:
19: // Act
20: view.Raise(v => v.Load += null, null, null);
21: presenter.ReleaseView();
22:
23: // Assert
24: Assert.AreEqual<string>(expectedPassword, view.Model.Password);
25: }
The attribute [TestMethod] comes from MSTest and [HostType(“Moles”)] comes from the Moles project. The last attribute tells the runtime to go Moles 
We use the Arrange, Act and Assert (AAA) method of testing our method, where we don’t expect the presenter to find the needed account, to see how it handles specific cases.
First we expect the password to display as “No success”, since the presenter displays this text if the password hasn’t been changed. Afterwards we mock our view and we create an instance of the presenter we want to test. Next we setup an empty account list, to simulate the missing account.
The last step sets up a redirect of the call to Domain.GetAccounts(“sitecore”), in order for us to mock the Sitecore calls. The MDomain is a class in the Sitecore.Kernel.Moles assembly with the namespace “Sitecore.Security.Domains.Moles”. We use the Moles naming convention of the Domain.GetDomain(string domain) to MDomain.GetDomainString and setup a delegate to handle the call. The delegate contains a mock of the domain we want to retrieve accounts from and setup the domain to return our list of accounts.
Lastly we act in normal fashion, as we raise the load event and releases the view. Afterwards we can assert that the password is as expected.
Admin account found but Memebership provider returns null
The next test assumes that the membership provider returns null:
1: [TestMethod]
2: [HostType("Moles")]
3: public void ViewLoadAdminAccountFoundButMembershipAccountIsMissing()
4: {
5: // Arrange
6: var username = "sitecore\\admin";
7: var expectedPassword = "No success";
8: var view = MockRepository.GenerateStub<IView<ChangePassword>>();
9: var presenter = new ResetAdminPasswordPresenter(view);
10: // Mock admin account
11: var adminAccount = MockRepository.GenerateMock<Account>(username, AccountType.User);
12: adminAccount.Stub(a => a.Name).Return(username);
13: // Create user list with admin account
14: var accounts = new List<Account>() { adminAccount };
15:
16: // Redirect Domain.GetDomain to our delegate
17: MDomain.GetDomainString = (s) =>
18: {
19: var dom = MockRepository.GenerateMock<Domain>(s);
20: dom.Stub(d => d.GetAccounts()).Return(accounts);
21: return dom;
22: };
23: // Mock user return from Membership db - return null
24: MMembership.GetUserString = (un) => null;
25:
26: // Act
27: view.Raise(v => v.Load += null, null, null);
28: presenter.ReleaseView();
29:
30: // Assert
31: Assert.AreEqual<string>(expectedPassword, view.Model.Password);
32: }
What’s changed is the account list which has an added account we are mocking (Supplying username and AccountType to the constructor). We are still redirecting the call to the domain and returning the account list, but now we also redirect the Membership.GetUser –call, because we want to mock the behavior of Sitecore. This first test method, we tell the runtime to return null, when GetUser is called with a string.
The test expects that a password has been set to “No success”, and thereby no exceptions are thrown.
Admin account and membership accounts return expected values, but reset password throws exception
The next test simulates that the ResetPassword method of the MemberShipUser throws an exception:
1: [TestMethod]
2: [HostType("Moles")]
3: public void ViewLoadAdminAccountFoundButMembershipPasswordResetThrowsException()
4: {
5: // Arrange
6: var username = "sitecore\\admin";
7: var expectedPassword = "No success";
8: var exceptionToThrow = new Exception("Cannot reset password");
9: var view = MockRepository.GenerateStub<IView<ChangePassword>>();
10: var presenter = new ResetAdminPasswordPresenter(view);
11: // Mock admin account
12: var adminAccount = MockRepository.GenerateMock<Account>(username, AccountType.User);
13: adminAccount.Stub(a => a.Name).Return(username);
14: // Create user list with admin account
15: var accounts = new List<Account>() { adminAccount };
16:
17: // Redirect Domain.GetDomain to our delegate
18: MDomain.GetDomainString = (s) =>
19: {
20: var dom = MockRepository.GenerateMock<Domain>(s);
21: dom.Stub(d => d.GetAccounts()).Return(accounts);
22: return dom;
23: };
24: // Mock user return from Membership db
25: // Mock ResetPassword to throw an exception
26: MMembership.GetUserString = (un) =>
27: {
28: var user = MockRepository.GenerateMock<MembershipUser>();
29: user.Stub(u => u.UserName).Return(un);
30: user.Stub(u => u.ResetPassword()).Throw(exceptionToThrow);
31: return user;
32: };
33:
34: // Act
35: view.Raise(v => v.Load += null, null, null);
36: presenter.ReleaseView();
37:
38: // Assert
39: Assert.AreEqual<string>(expectedPassword, view.Model.Password);
40: }
Here we change the GetUserString from a delegate that returns null to a delegate that returns a mocked MemberShipUser that throws an exception when calling ResetPassword.
Here we expect no Exceptions to be thrown and still expecting the password to be “No Success”.
Password updates
The last test case is when the password is updated:
1: [TestMethod]
2: [HostType("Moles")]
3: public void ViewLoadAdminPasswordUpdates()
4: {
5: // Arrange
6: var username = "sitecore\\admin";
7: var password = "abcd12345";
8: var view = MockRepository.GenerateStub<IView<ChangePassword>>();
9: var presenter = new ResetAdminPasswordPresenter(view);
10: // Mock admin account
11: var adminAccount = MockRepository.GenerateMock<Account>(username, AccountType.User);
12: adminAccount.Stub(a => a.Name).Return(username);
13: // Create user list with admin account
14: var accounts = new List<Account>() { adminAccount };
15:
16: // Redirect Domain.GetDomain to our delegate
17: MDomain.GetDomainString = (s) =>
18: {
19: var dom = MockRepository.GenerateMock<Domain>(s);
20: dom.Stub(d => d.GetAccounts()).Return(accounts);
21: return dom;
22: };
23: // Mock user return from Membership db
24: // Mock ResetPassword to return a value we can compare
25: MMembership.GetUserString = (un) =>
26: {
27: var user = MockRepository.GenerateMock<MembershipUser>();
28: user.Stub(u => u.UserName).Return(un);
29: user.Stub(u => u.ResetPassword()).Return(password);
30: return user;
31: };
32:
33: // Act
34: view.Raise(v => v.Load += null, null, null);
35: presenter.ReleaseView();
36:
37: // Assert
38: Assert.AreEqual<string>(password, view.Model.Password);
39: }
We setup a sunshine scenario where the password is updated. We do this by mocking the MemberShipUser to return a predefined password and Assert that the value of the View’s Model is equal to the expected password. Otherwise something would have gone wrong..
Outro
The above example shows how it’s possible to intercept calls to a static method or property in order to test Sitecore behavior via mocking.
Comments are welcome, since testing is rather new for me
.