I’ve been trying out JustMock Lite (hereon known as JML), from Telerik – the lite version is free and source available on Github. The package is installable via NuGet.
So let’s start with a simple Arrange-Act-Assert sample
IFeed feed = Mock.Create<IFeed>(); // arrange Mock.Arrange(() => feed.Update(10)).Returns(true).OccursOnce(); // act feed.Update(10); // assert Mock.Assert(feed);
The example above shows how we create a mock object based upon the IFeed interface. We then arrange the mocked methods etc. The next step in the sample above is where we use the mocked methods before finally setting assertions.
Note: We do not get a “mock” type back from Mock.Create as we would with a framework like Moq, but instead we get the IFeed which I rather like, not having to use the mock’s Object property to get the type being mocked. This is because in Moq the setup/arrange phase and for that matter the assert phase are all instance methods on the mock object, in JML we use static methods on the Mock class
Loose vs Strict
By default JML creates mocks with Behavior.Loose which means that we don’t need to supply all calls on the mock object upfront via the arrange mechanism. In other words, using Behavior.Loose simply means we might make calls on a mocked object’s methods (for example) without having to explicitly setup the Arrange calls and we’ll get default beaviour. Behavior.Strict means any calls we make on the mock object must have been set-up prior to being called on the mocked object.
Let’s look at an example of using JML’s strict behaviour
public interface IReader { IEnumerable<string> ReadLine(); string ReadToEnd(); } [Fact] public void ReadLine_EnsureCsvReaderUsesUnderlyingReader() { IReader reader = Mock.Create<IReader>(Behavior.Strict); Mock.Arrange(() => reader.ReadLine()).Returns((IEnumerable<string>)null); CsvReader csv = new CsvReader(reader); csv.ReadLine(); Mock.Assert(reader); }
In the above, assuming (for the moment) that csv.ReadLine() calls the IReader ReadLine method, then all will be work. But if we remove the Mock.Arrange call we’ll get a StrictMockException as we’d expect as we’ve not setup the Arrange calls. Switching to Behavior.Loose in essence gives us a default implementation of the IReader ReadLine (as we’ve not explicitly provided one via the Mock.Arrange method) and all will work again.
As per other mocking frameworks this simply means if we want to enforce a strict requirement for each call on our mocked object to first be arranged, then we must do this explicitly.
JML also has two other behaviors, Behavior.RecursiveLoose which allows us to create loose mocking on all levels of the mocked object.
The Behavior.CallOriginal sets the mock object up to, by default, call the actual mocked object’s methods/properties. Obviously this means it cannot be used on an interface or abstract method, but what it does mean is that we can mock a class’s virtual method/property (JustMock elevated – the commercial version of JustMock – looks like it supports non virtual/abstract mocking on classes) and by default call the original object’s methods and only Arrange those methods/properties we want to alter.
For example, the following code will pass our test as JML will call our original code and does not require we Arrange the return on the property Name
public class Reader { public virtual string Name { get { return "DefaultReader"; }} } [Fact] public void Name_ShouldBeAsPerTheImplementation() { Reader reader = Mock.Create<Reader>(Behavior.CallOriginal); Assert.Equal("DefaultReader", reader.Name); Mock.Assert(reader); }
In some mocking frameworks, such as Moq, will intercept the Name property call and return the default (null) value instead (assuming we’ve not setup any returns ofcourse).
More on CallOriginal
Behavior.CallOriginal sets up the mocked object as, by default, calling the original implementation code, but we can also setup Arrange calls to call the original implementation more explicitly.
For example
public class Reader { public virtual string GetValue(string key) { return "default"; } } Reader reader = Mock.Create<Reader>(); Mock.Arrange(() => reader.GetValue(null)).Returns("NullReader"); Mock.Arrange(() => reader.GetValue("key")).CallOriginal(); Assert.Equal("NullReader", reader.GetValue(null)); Assert.Equal("default", reader.GetValue("key")); Mock.Assert(reader);
So here when reader.GetValue is called with the argument “key” the original (concrete implementation) or the GetValue method is called.
Note: Moq also implements such a capability using the CallBase() method