In the spirit of Code Share Week, I’ve decided to share a base class we’ve been using for our test classes on my current project.
We’ve been using a Specification base class for our NUnit test classes, which is kind of following the BDD style of unit testing.
1: [TestFixture]
2: public class Specification
3: {
4: [SetUp]
5: public void Initialize()
6: {
7: Mocks = new MockRepository();
8: Before_each();
9: ReplayAll();
10: Because();
11: }
12:
13: [TearDown]
14: public void Cleanup()
15: {
16: After_each();
17: }
18:
19: protected virtual void Before_each() { }
20: protected virtual void After_each() { }
21: protected virtual void Because() { }
22:
23: public MockRepository Mocks { get; private set; }
24:
25: protected T Mock<T>() where T : class
26: {
27: return MockRepository.GenerateMock<T>();
28: }
29:
30: protected T Stub<T>() where T : class
31: {
32: return MockRepository.GenerateStub<T>();
33: }
34:
35: protected T Stub<T>(params object[] args) where T : class
36: {
37: return MockRepository.GenerateStub<T>(args);
38: }
39:
40: protected T Partial<T>() where T : class
41: {
42: return Mocks.PartialMock<T>();
43: }
44:
45: protected T Partial<T>(params object[] args) where T : class
46: {
47: return Mocks.PartialMock<T>(args);
48: }
49:
50: protected void Raise(object mock, string eventName, object sender, EventArgs args)
51: {
52: new EventRaiser((IMockedObject)mock, eventName).Raise(sender, args);
53: }
54:
55: protected virtual void ReplayAll()
56: {
57: Mocks.ReplayAll();
58: }
59:
60: protected void spec_not_implemented()
61: {
62: MethodBase caller = new StackTrace().GetFrame(1).GetMethod();
63:
64: spec_not_implemented(caller.DeclaringType.Name + "." + caller.Name);
65: }
66:
67: protected void spec_not_implemented(string specName)
68: {
69: Console.WriteLine("Specification not implemented : " + specName);
70: }
71:
72: }
Here’s a typical specification written to test user account creation.
1: public class When_creating_a_new_user_account : Specification
2: {
3: private IThirdPartyUserService _thirdPartyUserService;
4: private IUserDetailController _userDetailController;
5: private CreateUserCommand _newUserCommand;
6: private UserService _userService;
7:
8: protected override void Before_each()
9: {
10: _thirdPartyUserService = Stub<IThirdPartyUserService>();
11: _userDetailController = Stub<IUserDetailController>();
12: var lookupService = Stub<ILookupService>();
13: var logService = Stub<ILogService>();
14: var encryptionService = Stub<IEncryptionService>();
15: _newUserCommand = new CreateUserCommand();
16: _thirdPartyUserService.Stub(tpus => tpus.CreateUser(_newUserCommand)).Return("fakeAuthTicket");
17: encryptionService.Stub(es => es.Encrypt(_newUserCommand.Password)).Return(_newUserCommand.Password);
18: _userService = new UserService(_thirdPartyUserService, _userDetailController,
19: logService, lookupService, encryptionService);
20: }
21:
22: protected override void Because()
23: {
24: _userService.CreateUser(_newUserCommand);
25: }
26:
27: [Test]
28: public void Should_call_the_ThirdParty_user_service()
29: {
30: _thirdPartyUserService.AssertWasCalled(tpus => tpus.CreateUser(_newUserCommand));
31: }
32:
33: [Test]
34: public void Should_call_the_UserDetailController_to_persist_data()
35: {
36: _userDetailController.AssertWasCalled(udc => udc.Insert(_newUserCommand.Login,
37: _newUserCommand.Password, _newUserCommand.Email));
39: }
One problem we ran into was that the UserService class kept having dependencies added as more functionality was added to the class. We’re using StructureMap as an IoC container, so there’s no impact to code when you add a dependency to a constructor, but it was requiring us to refactor our tests since we’re not using StructureMap to create instances inside of our tests.
StructureMap comes with a separate assembly containing the RhinoAutoMocker which my colleague Jon Kruger suggested would solve our constant refactoring problem. You can use the auto mocker functionality to automatically mock all dependencies of a class. This also cleans up your code because you don’t have to create fields for dependencies that you plan on using in multiple test methods.
3: private RhinoAutoMocker<UserService> _mocker;
4: private IThirdPartyUserService _thirdPartyUserService;
5: private IUserDetailController _userDetailController;
6: private CreateUserCommand _newUserCommand;
10: _mocker = new RhinoAutoMocker<UserService>();
11: _newUserCommand = new CreateUserCommand();
12: _thirdPartyUserService = _mocker.Get<IThirdPartyUserService>();
13: _thirdPartyUserService.Stub(tpus => tpus.CreateUser(_newUserCommand))
14: .Return("fakeAuthTicket");
15: _userDetailController = _mocker.Get<IUserDetailController>();
16: _mocker.Get<IEncryptionService>().Stub(es => es.Encrypt(_newUserCommand.Password))
17: .Return(_newUserCommand.Password);
18: }
19:
20: protected override void Because()
21: {
22: _mocker.ClassUnderTest.CreateUser(_newUserCommand);
23: }
25: [Test]
26: public void Should_call_the_ThirdParty_user_service()
27: {
28: _thirdPartyUserService.AssertWasCalled(tpus => tpus.CreateUser(_newUserCommand));
29: }
30:
31: [Test]
32: public void Should_call_the_UserDetailController_to_persist_data()
33: {
34: _userDetailController.AssertWasCalled(udc => udc.Insert(_newUserCommand.Login,
35: _newUserCommand.Password, _newUserCommand.Email));
36: }
37: }
I took this a step further and created a base class that is used when you’re only testing one class. It doesn’t add all that much functionality, but it does make your specs look much cleaner.
1: public class AutoMockingSpecification<T> : Specification
2: where T : class
4: private bool _replayTheClassUnderTest = false;
5:
6: public RhinoAutoMocker<T> Mocker { get; set; }
10: base.Before_each();
11: Mocker = new RhinoAutoMocker<T>();
12: }
13:
14: protected override void ReplayAll()
16: base.ReplayAll();
17: if (_replayTheClassUnderTest)
18: Mocker.ClassUnderTest.Replay();
19: }
20:
21: public virtual void PartialMockTheClassUnderTest()
22: {
23: Mocker.PartialMockTheClassUnderTest();
24: _replayTheClassUnderTest = true;
26: }
Here’s our sample UserService specification refactored to use the AutoMockingSpecification base class.
1: public class When_creating_a_new_user_account : AutoMockingSpecification<UserService>
3: private CreateUserCommand _newUserCommand;
4:
5: protected override void Before_each()
7: base.Before_each();
8: _newUserCommand = new CreateUserCommand();
9: Mocker.Get<IThirdPartyUserService>().Stub(tpus => tpus.CreateUser(_newUserCommand))
10: .Return("fakeAuthTicket");
11: Mocker.Get<IEncryptionService>().Stub(es => es.Encrypt(_newUserCommand.Password))
12: .Return(_newUserCommand.Password);
13: }
14:
15: protected override void Because()
16: {
17: Mocker.ClassUnderTest.CreateUser(_newUserCommand);
20: [Test]
21: public void Should_call_the_ThirdParty_user_service()
23: Mocker.Get<IThirdPartyUserService>().AssertWasCalled(tpus => tpus.CreateUser(_newUserCommand));
24: }
25:
26: [Test]
27: public void Should_call_the_UserDetailController_to_persist_data()
28: {
29: Mocker.Get<IUserDetailController>().AssertWasCalled(
30: udc => udc.Insert(_newUserCommand.Login, _newUserCommand.Password, _newUserCommand.Email));
32: }
I’m pleased with the result, and it seems to be pretty popular with the other developers on our project.
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.