NMock

Intro to NMock

If you do Test Driven Development (TDD) for any amount of time and with any amount of serious effort you are going to run across a problem. Sometimes you can’t test one object without other objects being involved. Since you can’t properly test one object without isolating it, you need to fake or mock the others that you aren’t testing. The Wikipedia entry on Mock Objects discusses it in some more detail.

A good candidate for a mock are objects that return current information (and as such are hard to properly test) or objects that will make permanent changes to databases, for instance, and as such are also poor candidates for repeatable testing.

The first (and only) mocking framework that I’ve used is NMock. I chose it because my rule is “when in doubt, choose the product that is named ‘n’ and then what you are doing” (remember my NLog and NUnit posts?).

Examine the code below and my comments about what each section is doing.

using System;
using NMock2;

namespace PeteOnSoftware
{
    public interface IBlogEntry
    {
        string PostName { get; set; }
        DateTime PostingDate { get; set; }
        string PostBody { get; set; }
        bool SavePost();
    }

    public class NMock
    {
        public static void MakeMocks()
        {
            // Create the Mock Object "factory"
            var mockery = new Mockery();

            // Create our mock object based on the interface defined above
            IBlogEntry mockBlogEntry = (IBlogEntry) mockery.NewMock(typeof (IBlogEntry));

            // Here is the awesome part.  Here is where we define our Mock behavior.  Not only will 
            // our object now return true when the SavePost() method is called and "Intro to NMock" 
            // when the PostName property is called, but it will only do it one time - as we have
            // defined here.
            Expect.Once.On(mockBlogEntry).Method("SavePost").WithNoArguments().Will(Return.Value(true));
            Expect.Once.On(mockBlogEntry).GetProperty("PostName").Will(Return.Value("Intro to NMock"));

            // Output the results to the screen to see if it is behaving as we expect.
            Console.WriteLine(mockBlogEntry.SavePost());
            Console.WriteLine(mockBlogEntry.PostName);
        }
    }
}

This outputs the following to the output window:

True
Intro to NMock

However, check out the following code:

using System;
using NMock2;

namespace PeteOnSoftware
{
    public interface IBlogEntry
    {
        string PostName { get; set; }
        DateTime PostingDate { get; set; }
        string PostBody { get; set; }
        bool SavePost();
    }

    public class NMock
    {
        public static void MakeMocks()
        {
            var mockery = new Mockery();

            IBlogEntry mockBlogEntry = (IBlogEntry) mockery.NewMock(typeof (IBlogEntry));

            Expect.Once.On(mockBlogEntry).Method("SavePost").WithNoArguments().Will(Return.Value(true));

            // Output the results to the screen to see if it is behaving as we expect.
            Console.WriteLine(mockBlogEntry.SavePost());
            Console.WriteLine(mockBlogEntry.PostName);

            // We told the mock earlier that we would only call SavePost() once.  Let's see what 
            // happens if we call it again.
            Console.WriteLine(mockBlogEntry.SavePost());
        }
    }
}

This returns the following exception:

Unhandled Exception: NMock2.Internal.ExpectationException: 
     unexpected invocation  of blogEntry.SavePost()

One application of how that could be useful would be if you are testing your business tier to make sure that it does not call Save() on an object or into the DataTier more than one time per invocation. There are other options, as well. You can say Expect.AtLeastOnce or Expect.AtLeast(some int) or Expect.AtMost or Expect.Between or Expect.Never. The framework is so flexible. You can define how you want the mock object to behave depending on its inputs.

Examine the following code that makes the SavePost method return true if passed 1 and false if passed -1.

using System;
using NMock2;

namespace PeteOnSoftware
{
    public interface IBlogEntry
    {
        string PostName { get; set; }
        DateTime PostingDate { get; set; }
        string PostBody { get; set; }
        bool SavePost(int id);
    }

    public class NMock
    {
        public static void MakeMocks()
        {
            var mockery = new Mockery();

            IBlogEntry mockBlogEntry = (IBlogEntry) mockery.NewMock(typeof (IBlogEntry));

            Expect.AtLeastOnce.On(mockBlogEntry).Method("SavePost").With(1).Will(Return.Value(true));
            Expect.AtLeastOnce.On(mockBlogEntry).Method("SavePost").With(-1).Will(Return.Value(false));
            
            Console.WriteLine(mockBlogEntry.SavePost(1));
            Console.WriteLine(mockBlogEntry.SavePost(-1));
        }
    }
}

As you can see, NMock is flexible and can be very useful to a programmer who is doing unit tests. Next time, I’d like to take a look at Dependency Injection / Inversion of Control and how it can be used with Mocking to not only make your code flexible, but very testable.

One comment Intro to NMock

Nice article Pete.

Some comments about your sample code:

IBlogEntry mockBlogEntry = (IBlogEntry) mockery.NewMock(typeof (IBlogEntry));

you can use

IBlogEntry mockBlogEntry = mockery.NewMock();

Expect.Once.On(mockBlogEntry).Method(“SavePost”).WithNoArguments().Will(Return.Value(true));

WithNoArguments is not needed if this is the only overload.

If you want to have a look at the latest and (hopefully) greatest version then have a look at http://sourceforge.net/projects/nmock2/ which is based on the version from nmock.org and offers a bunch of new functionality.

Happy mocking
Urs

Leave a Reply

Your email address will not be published. Required fields are marked *