CodeBork | Tales from the Codeface

The coding blog of Alastair Smith, a software developer based in Cambridge, UK. Interested in DevOps, Azure, Kubernetes, .NET Core, and VueJS.


Project maintained by Hosted on GitHub Pages — Theme by mattgraham

To aid the testing of my personal finance program, I’ve been making heavy use of the NMock mocking framework for .NET. This is a cool utility that allows you replace actual code calls with mock code calls, factoring out a lot of complexity of setting up some tests. For example, I first started using it to mock the log4net logging framework rather than creating a new logger for each test/suite and passing that around. More recently, I’ve found it useful in mocking parts of the plug-in framework that are required by the code but not part of the test (such as the preferences’ manager, for example). By way of example, here’s set-up method from one of my plug-ins’ test suite:

public void SetUp() { mocks = new Mockery(); logger = mocks.NewMock(); pluginFramework = mocks.NewMock(); prefsManager = new PreferencesManager(); Expect.Exactly(4).On(logger).Method("Info"); prefsManager.Initialise(logger, prefsFile, prefsFile); Expect.Once.On(logger).Method("Info"); pluginBroker = new PluginBroker(logger, pluginFramework); Expect.Once.On(logger).Method("Info"); Expect.Once.On(logger).Method("InfoFormat"); Expect.Exactly(2).On(pluginFramework).GetProperty("PreferencesManager").Will(Return.Value(prefsManager)); pluginBroker.Initialise(pluginDir); Expect.Once.On(logger).Method("Info"); messageBroker = new MessageBroker(); messageBroker.Initialise(logger); Expect.AtLeastOnce.On(pluginFramework).GetProperty("MessageBroker").Will(Return.Value(messageBroker)); Expect.AtLeastOnce.On(pluginFramework).GetProperty("PluginBroker").Will(Return.Value(pluginBroker)); Expect.AtLeastOnce.On(pluginFramework).GetProperty("PreferencesManager").Will(Return.Value(prefsManager)); } </blockcode> The NMock statements are those that start Expect.Number_Of_Times.On(mock_object). As you can see, the statements read very much like English, which I think is one of the strengths of the framework. You can immediately tell what the expectation of this object is without having to think around the syntax of the framework. Note too the heavy use of interfaces: NMock can only mock interfaces, which I think is another strength of the framework. This focus on interfaces really drives to you programming via interfaces, which is a key part of designing by contract. So what does this code do? First of all, it creates a Mockery object, which is essentially a factory object for mock objects. Next, a mock logger and mock plug-in framework object are created. A real PreferencesManager is created, and we tell NMock that we expect exactly 4 calls to logger.Info in the Initialise method of PreferencesManager. The same is done for a PluginBroker and its Initialise method. Notice here that we're specifying too that the property PluginBroker.PreferencesManager will return a specific value, i.e., the PreferencesManager created earlier. A MessageBroker is then created in the same way. Finally, we state that we expect the properties MessageBroker, PluginBroker and PreferencesManager on pluginFramework will return the concrete objects already created. At the end of each test, which may contain further expectations of our mocked objects, we can run Mockery.VerifyAllExpectationsHaveBeenMet(), which does exactly what it says on tin (a victory for clear over concise method naming!). Note, however, that this is an instance method and not a static one, so you'll need to call it on the Mockery object created at the beginning. NMock has a certain amount of flexibility in its interface. For example, you can replace Expect.x with Stub, which is equivalent to Expect.AtLeast(0). There is also a raft of quantifiers for expectations in addition to Once and AtLeast(x), such as Between(x, y) and Never. The downside of NMock is that your expectations end up littered with strings referencing parts of the API. If a mocked part of the API changes, you have to update these so-called "magic" strings with the appropriate new values; it also enforces a certain amount of trial and error when initially testing your expectations. A framework like Rhino Mocks will use the compiler to tell you when you've messed up by allowing you to reference the mocked properties on the mock object directly, e.g.: IFramework pluginFramework; // Create stub framework object via Rhino Mocks IPreferencesManager prefsMan; // Create and initialise preferences' manager as above pluginFramework.PreferencesManager = prefsMan; This is obviously more concise than the NMock equivalent, listed in the last line of the first code block. Mocking frameworks are a very useful addition to the unit testing toolkit that allow you to abstract away some of the complexities of setting up unit tests. They can also be used to test that an interface correctly obeys its contract. Testing the contract should not, however, be confused with exercising the actual code in the implementation. If you haven't already investigated mocks, why not look at incorporating one such framework into your next project's unit tests?