Moq examples, Part II 58
A few blog articles ago I showed some examples using Moq. I created those examples in anticipation of using Moq in a TDD class with a group in Canada.
What I ended up creating was different for a number of reasons. The final version is somewhat cleaned up compared to those first examples, so here are those examples as well: actual test class created.
These tests are not really that different from the first version, other than I did not use exceptions as much.
After the underlying LoginService was created with these tests, I had the students refactor to the GoF State Design Pattern. If you’re feeling like a little practice, consider:- Creating one test at a time
- Write the underlying service
- When all tests are passing, try to refactor to the state pattern.
It’s a good exercise. The guys in Canada seemed to really grok Moq and started using it to characterize their actual code the next day.
Strict Mocks and Characterization Tests 16
This week I worked with a great group in Canada. This group of people had me using Moq for the first time and I found it to be a fine mocking tool. In fact, it reminded me of why I think the Java language is now far outclassed by C# and only getting more behind (luckily the JVM has many languages to offer).
One issue this group is struggling with is a legacy base with several services written with static API’s. These classes are somewhat large, unwieldy and would be much improved with some of the following refactorings:- Replace switch with polymorphism
- Replace type code with strategy/state
- Introduce Instance Delegator
- Use a combination of template method pattern + strategy and also strategy + composite
This is actually pretty standard stuff and this group understands the way forward. But what of their existing technical debt?
Today we picked one method in particular and attempted to work our way through it. This method was a classic legacy method (no unit tests). It also had a switch on type and then it also did one or more things based on a set of options. All of this was in one method.
If you read Fowler’s Refactoring Book, it mentions a combination of encapsulating the type code followed by replacing switch with polymorphism for the first problem in this method (the switch). We were able to skip encapsulating the type code since we wanted to keep the external API unchanged (legacy code).
So we first created a base strategy for the switch and then several empty derived classes, one for each of the enums. This is a safe legacy refactoring because it only involved adding new code.
Next, we created a factory to create the correct strategy based on the type code and added that to the existing method (we also added a few virtual methods). Again, a safe refactoring since it only involved adding effectively unused code (we did create the factory using nearly strict TDD). Finally, we delegated from the original method to the strategy returned from the factory. Safe again, since we had tested the factory.
So far, so good. But next, we wanted to push the method down to each of the subclasses and remove the parts of the logic that did not apply to each given type. We did a spike refactoring to see what that’d be like and it was at least a little dicey. We finally decided to get the original method under test so that as we refactored, we had the safety net necessary to refactor with confidence.
We started by simply calling the method with null’s and 0 values. We worked our way through the method, adding hand-rolled test doubles until we came across our first static class.
Their current system has DAO’s with fully static interfaces. This is something that is tough to fake (well we were not using and AOP framework, so …). Anyway, this is where we introduced the instance delegator. We:- Added an instance of the class as a static member (essentially creating a singleton).
- Added a property setter and getter (making it an overridable singleton).
- We then copied the body of the static method into an instance method, which we made virtual.
- We then delegated the static method to the virtual method.
- Then, in the unit test, we set the singleton to a hand-coded test double in the setup and reset the singleton in the tear down method.
We had to do this several times and on the third time (I think it was the third time), the hand-rolled test double would have had to implement several (17ish) methods and it became clear that we were ready to use a mocking framework. They are using Moq so we started using Moq to accomplish the remainder of the mocking.
After some time, we managed to get a test that essentially sent a tracer bullet through one path of the method we wanted to get under test. When the test turned green there was much rejoicing.
However, we had to ask the question: “So what are we testing?” After some discussion, we came up with a few things:- This method currently makes calls to the service layers and those calls depend on both an enumeration (replaced with a shallow and wide hierarchy of strategies) and options (to be replaced with a composition of strategies).
- It also changes some values in an underling domain object.
So that’s what we needed to characterize.
We had a discussion on this and as a group. We wanted a way to report on the actual method calls so we could then assert (or in Moq parlance Verify). We looked at using Moq’s callbacks, but it appears that those are registered on a per-method basis. We briefly toyed with the idea of using an AOP tool to introduce tracing, but that’s for another time (I’m thinking of looking into it out of curiosity) but we decided that we could instead do the following:- Begin as we already had, get through the method with a tracer.
- Determine the paths we want to get under test.
- For each path:
- Create a test using strict mocks (which fail as soon as an unexpected method is called)
- Use a Setup to document this call as expected – this is essentially one of the assertions for the characterization test.
- Continue until we have all the Setups required to get through the test.
- Add any final assertions based on state-based checks and call VerifyAll on the Moq-based mock object.
This would be a way we could work through the method and characterize it before we start refactoring it in earnest.
This might sound like a lot of work and it certainly is no cake walk, but all of this work was done by one of the attendees and as a group they certainly have the expertise to do this work. And in reality, it did not take too long. As they practice and get some of the preliminary work finished, this will be much easier.
Overall, it was a fun week. We:- Spent time on one project practicing TDD and refactoring to patterns (they implemented 5 of the GoF patterns).
- Spent time practicing some of Fowler’s refactorings and Feather’s legacy refactorings.
- Spent a day practicing TDD using mocks for everything but the unit under test. At the end they had a test class, one production class and several interfaces.
In retrospect, the work they did in the first three days was nearly exactly what they needed to practice for the final day of effort. When we started tackling their legacy code, they had already practiced everything they used in getting the method under test.
So overall great week with a fun group of guys in Canada.
A First Look at Moq 46
This week I’m working with a customer that uses two tools I have not previously used: MBUnit (instead of NUnit, and it is now part of Gallio [sic]) and Moq (by Daniel Cazzulino).
For how I’m using MBUnit, there are no differences (that’s not to say it’s the same as NUnit, I’m just using it that way). However, Moq is a different mocking framework.
While you can do something similar to a record/playback approach, Moq encourages a different approach. Rather than try to describe it, I’ll show a few examples and you can decide for yourself (or you can tell me how I should have done it better).
Background
Given a login service, I want to make sure it follows a set of requirements. The list of requirements I typically use for this example are here: http://schuchert.wikispaces.com/Tdd.Problems.LoggingIn. What follows are tests that are similar to, but not quite consistent with those requirements.When I was working through this example, I was a little exception happy. I was trying to learn how to make certain things happen with the moq. I’ve simply repeated my experiments here, when I use this later on, I’ll approach this problem a bit differently.
Example 1: Logging in successfully
00: [Test]
01: public void WhenUserFoundAndPasswordMatchesUserShouldBeLoggedIn()
02: {
03: var userMock = new Mock<IUser>();
04: userMock.Setup(user => user.PasswordMatches(It.IsAny<string>())).Returns(true);
05:
06: var daoMock = new Mock<IUserDao>();
07: daoMock.Setup(dao => dao.Get(It.IsAny<string>())).Returns(userMock.Object);
08:
09: var service = new UserService(daoMock.Object);
10: service.Login("Brett", "password");
11:
12: userMock.VerifySet(user => user.LoggedIn = true);
13: }
Line 3 | Create a userMock. |
Line 4 | Using a C# lambad, when a user object is sent the PasswordMatched message with any string object, return true. |
Line 6 | Create a mock IUserDao. |
Line 7 | Whenever the Get method is called with any string, return the userMock’s Object property (the actual mock object). |
Line 9 | Create a user service and inject into it the daoMock’s Object property (the actual dao mock). |
Line 10 | Send the login message, which should result in the User being logged in. |
Line 12 | Verify that the LoggedIn property was set to true. |
Notice that rather than setting expectations, line 12 verifies only what I want to verify. It is possible to call Setup more times and then use “VerifyAll” to confirm all the Setup’s were actually used. However, that makes the test more coupled to the underlying implementation. All I care about is that as a result of this configuration of objects, a user was LoggedIn.
By default, mocks are not strict. That is, code may call any methods it wishes on a give mock object. So the default behavior is more like a stub than a mock object. If you call “VerifyAll” on the userMock or the daoMock, then all of the descriptions in the various Setup method invocations need to happen.
Example 2: User not found? Throw an exception
00: [Test]
01: [ExpectedException(typeof(UserDoesNotExistException))]
02: public void WhenUserNotFoundShouldThrowException()
03: {
04: var daoMock = new Mock<IUserDao>();
05: daoMock.Setup(dao => dao.Get(It.IsAny<string>())).Returns((IUser) null);
06:
07: var service = new UserService(daoMock.Object);
08: service.Login("Brett", "password");
09: }
Line 1 | Create an IUserDao mock. |
Line 5 | When Get is called with any string, return null – that is, never find an object. I think of this as a kind of Saboteur, which is a specific kind of stub. |
Line 7 | Create a user service and inject the daoMock.Object property, the actual mock. |
Line 8 | Call the Login method, which should throw an exception for this test to pass. |
Notice that this example includes another non-strict mock. You can call it as often as you wish and there’s no checking on the methods called. However, this stub should force the implementation of the Login method to throw a UserDoesNotExist exception.
Example 3: Throw an Exception if the password does not match
00: [Test]
01: [ExpectedException(typeof(PasswordDoesNotMatchException))]
02: public void WhenLoginAttemptDoesNotMatchPasswordThrowsException()
03: {
04: var userMock = new Mock<IUser>();
05: userMock.Setup(user => user.PasswordMatches(It.IsAny<string>())).Returns(false);
06:
07: var daoMock = new Mock<IUserDao>();
08: daoMock.Setup(dao => dao.Get(It.IsAny<string>())).Returns(userMock.Object);
09:
10: var service = new UserService(daoMock.Object);
11: service.Login("", "");
12: }
Line 4 | Create an IUser mock. |
Line 5 | Whenever the PasswordMatches method is called with any string, it will return false. All passwords are wrong! |
Line 7 | Create an IUserDao mock. |
Line 8 | Whenever Get is called with any string on the IUserDao mock object, return the userMock.Object property (the real mock object). |
Line 10 | Create a UserService, injecting the daoMock.Object property (the real IUserDao mock). |
Line 11 | Logging in with any user/password combination should now throw a PasswordDoesNotMatchException. |
Eample 4: Three failed login attempts should cause user account to be revoked.
00: [Test]
01: public void WhenLoginAttemptThreeTimesInARowWithInvalidPasswordUserRevoked()
02: {
03: var userMock = new Mock<IUser>();
04: userMock.Setup(user => user.PasswordMatches(It.IsAny<string>())).Returns(false);
05:
06: var daoMock = new Mock<IUserDao>();
07: daoMock.Setup(dao => dao.Get(It.IsAny<string>())).Returns(userMock.Object);
08:
09: var service = new UserService(daoMock.Object);
10: for (int i = 0; i < 3; ++i)
11: AttempLoginIgnoringException(service, "");
12:
13: userMock.VerifySet(user => user.Revoked = true);
14: }
Lines 3 – 4 | Create an IUser mock (stub or Saboteur really) that will not match any password. |
Lines 6 – 7 | Create an IUserDao mock (stub) that will return the userMock.Object for all calls to Get with any string. |
Line 9 | Create a UserService, injecting the IUserDao mock object. |
Lines 10 – 11 | Attempt to login 3 times, each of which will fail. |
Line 13 | Verify that the user.Revoked property was set to true on the userMock object. |
Example 5: Failing 2x with one account and then switching to another account and failing again does not revoke account.
00: [Test]
01: public void LoginWrongPassword2XandThenSwitchAccountsWithWrongPassowrdNothingRevoked()
02: {
03: var userMock1 = new Mock<IUser>();
04: userMock1.Setup(user => user.PasswordMatches(It.IsAny<string>())).Returns(false);
05:
06: var userMock2 = new Mock<IUser>(MockBehavior.Strict);
07: userMock2.Setup(user => user.PasswordMatches(It.IsAny<string>())).Returns(false);
08:
09: var daoMock = new Mock<IUserDao>();
10: daoMock.Setup(dao => dao.Get("user1")).Returns(userMock1.Object);
11: daoMock.Setup(dao => dao.Get("user2")).Returns(userMock2.Object);
12:
13: var service = new UserService(daoMock.Object);
14:
15: AttempLoginIgnoringException(service, "user1");
16: AttempLoginIgnoringException(service, "user1");
17: AttempLoginIgnoringException(service, "user2");
18:
19: userMock2.VerifyAll();
20: }
Lines 3 – 4 | Create user mock that will not match any password. |
Lines 6 – 7 | Ibid, but this is a strict mock. That is, other than PasswordMatches, no other methods/properties should be called/used (we do not want it’s Revoked property to be set or even called). |
Lines 9 – 11 | Create an IUserDao mock. Whenever Get is called with “user1”, return userMock1.Object. Whenever Get is called with “user2”, return userMock2. Object. |
Lines 12 | Create the UserService injecting the daoMock.Object. |
Lines 15 – 16 | Attempt login 2x to account User1, both will fail. |
Line 17 | Attempt login to account User2, which will also fail, but we do not want the user2 account revoked. |
Line 19 | Verify all, meaning that only the PasswordMatches method was called on userMock2.Object. If any other methods were called, the test will fail. |