Telerik blogs

In Doing Your First Mock, Mehfuz Hossain explained why you should use mocking to improve your unit tests and then used a real world example to demonstrate this technique. In this post, I will take you down a different path using other forms of stand-ins.

I will cover three types of objects used to improve unit testing:

  • Fakes
  • Stubs
  • Mocks

These objects will be demonstrated using a SecurityHandler class which has been designed to allow injection of an interface in the constructor.

public class SecurityHandler
{
    private readonly ILoginService _service;
    public int UserID { get; internal set; }
    public SecurityHandler(ILoginService service)
    {
        _service = service;
    }
    public bool LoginUser(string userName, string password)
    {
        return (UserID = _service.ValidateUser(userName, password)) != 0;
    }
}

There are two scenarios expected from this class:

  • When a user successfully logs into the system, the userid should be retrieved from the database and made available to consumers of the SecurityHandler.
  • When a user fails to login, the userid should be set to zero.

Fakes

A fake is a class that you can use instead of actual line of business code.  A fake implementation might look something like this:

public class FakeLoginService:ILoginService
{
    public int ValidateUser(string userName, string password)
    {
        return 5;
    }
}

This code contains no real business functionality; it is hard coded to return 5. However, it does provide two important benefits:

  • It allows you to write your first unit test. 
  • It eliminates the need for a real Login Service, isolating dependent code from integration issues.

For this test, I will first create an instance of the SecurityHandler, injecting the fake for the service dependency. I will then execute the LoginUser method. Since the fake returns a non-zero integer, it is expected that the method will return true and that the UserID property of the handler is correctly set to the returned ID from the LoginService. I am using NUnit for these examples, but any common unit testing framework will do.

[Test]
public void Should_Return_True_With_Valid_Username_And_Password()
{
    SecurityHandler handler = new SecurityHandler(new FakeLoginService());
    Assert.IsTrue(handler.LoginUser(string.Empty, string.Empty));
    Assert.AreEqual(handler.UserID, 5);
}

Looking at this test, it validates the “happy path” of our security handler.  If I use a code coverage tool, I could also validate that the line of business code is completely covered by the test. In addition to code coverage, there is another extremely important concept with unit testing: use case coverage. This test does not cover the situation where the user has entered an invalid userid/password combination.

In order to do this with a fake, I will need to write another class (perhaps called FakeFailingLoginService) and create another unit test to verify that this code successfully handles the “unhappy” path. I’m all for creating another test to evaluate a different execution path, but creating another implementation to hard code a failing login is too much friction.  There are better things to do with your time than writing repetitive code.

Stubs

Martin Fowler defines Stubs as objects “that provide canned answers to calls made during the test.” This might seem the same as the fake written above, but the biggest difference is that a mocking framework like JustMock can be used to create the stub in the test, providing the necessary scaffolding for the system under test in very little code.

I will accomplish this by creating a loose mock, arrange for how that object should behave when called, and then pass it into the SecurityHandler. This happens because the JustMock framework creates a proxy that wraps the interface, which is treated like a real implementation of the interface.

To demonstrate this, I will delete the FakeLoginService from the solution and rewrite the test as follows:

[Test]
public void Should_Return_True_With_Valid_Username_And_Password()
{
    string userName = "Bob";
    string password = "Password";
    ILoginService service = Mock.Create<ILoginService>();
    Mock.Arrange(() => service.ValidateUser(userName, password)).Returns(5);
    SecurityHandler handler = new SecurityHandler(service);
    Assert.IsTrue(handler.LoginUser(userName, password));
    Assert.AreEqual(handler.UserID, 5);
}

What exactly is going on here? On line 6, I am creating the proxy for the LoginService interface. This is an important first step, as you cannot instantiate an interface. The following line replaces the need for the fake created above. I am arranging how the stub will behave when called.  This line can be translated to “when the method ValidateUser is called on the service object and the parameters ‘Bob’ and ‘Password’ are passed in, return the number 5.”

This proxy is then passed in as the dependency for the SecurityHandler. When LoginUser is called on the handler, it executes the arranged method on the proxy in this line:

return (UserID = _service.ValidateUser(userName, password)) != 0;

Everything works as expected, the test passes, and I’m done, right?  Not quite yet. One of the drawbacks of using a fake object was the extra code needed to cover the various use cases. With a stub, this becomes trivial as the following test shows:

[Test]
public void Should_Return_False_With_Invalid_Username_And_Password()
{
    string userName = "Bob";
    string password = "Password";
    ILoginService service = Mock.Create<ILoginService>();
    Mock.Arrange(() => service.ValidateUser(userName, password)).Returns(0);
    SecurityHandler handler = new SecurityHandler(service);
    Assert.IsFalse(handler.LoginUser(userName, password));
    Assert.AreEqual(handler.UserID, 0);
}

The requirements state that if the user fails to login, the service should return a zero.  The security handler then reflects that failure by setting the UserID property to zero as well.

In JustMock terms, a stub is a loose mock and is the default type of the created proxy.  Any method on the stub that gets called but wasn’t specifically arranged will still succeed, returning the default value for the return type.  In this example, if the call to ValidateUser was not arranged, it would return zero; the default value for the integer data type.

I could have written the failing login test without the arrangement (see the code sample below), but that would certainly make the code less readable. The reader would have to know what the default behavior is for a method that isn’t arranged.

[Test]
public void Should_Return_False_With_Invalid_Username_And_Password()
{
    string userName = "Bob";
    string password = "Password";
    ILoginService service = Mock.Create<ILoginService>();
    SecurityHandler handler = new SecurityHandler(service);
    Assert.IsFalse(handler.LoginUser(userName, password));
    Assert.AreEqual(handler.UserID, 0);
}

An important facet of unit testing, in addition to validating the line of business code, is to provide a mechanism for another developer to be able to quickly understand what the code does and doesn’t do, and to convey the “spirit” of the code.

It is easy to see the benefits of using a stub over a fake, but one shortfall for stub objects is the lack of support for Behavior Specification. I caught (and unfortunately wrote) my share of bugs where there was an assumption that a block of code was being executed when in fact it was not.

For example, what if the SecurityHandler is modified to the following code block:

public class SecurityHandler
{
    private readonly ILoginService _service;
    public int UserID { get; internal set; }
    public SecurityHandler(ILoginService service)
    {
    }
    public bool LoginUser(string userName, string password)
    {
        UserID = 5;
        return true;
        //return (UserID = _service.ValidateUser(userName, password)) != 0;
    }
}

Don’t laugh! I once had a developer do this because the service wasn’t ready, and he wanted to check his code in.  This code made it all of the way to QA! (This particular developer had not written a single unit test either.)

I need a way to confirm that the ValidateUser method of the LoginService object actually gets called, and this cannot be done with a traditional stub.

Mocks

Mocks bring all of the benefits of stubs plus the ability to specify behavior. To demonstrate this, I will add behavior checking to the test. The first change is to verify that the arranged method was actually called. Using JustMock, this will require some minor changes to the test.  As you can see in the following code sample, the keyword Occurs(1) is added to the end of the call to Mock.Arrange. This creates the expectation that this method will be called once, and only once.

The second change to the test is to add the line Mock.Assert(service). The call to Mock.Assert tells the JustMock framework to check all expectations and throw an exception if everything didn’t occur exactly as arranged.

[Test]
public void Should_Return_True_With_Valid_Username_And_Password()
{
    string userName = "Bob";
    string password = "Password";
    ILoginService service = Mock.Create<ILoginService>();
    Mock.Arrange(() => service.ValidateUser(userName, password)).Returns(5).Occurs(1);
    SecurityHandler handler = new SecurityHandler(service);
    Assert.IsTrue(handler.LoginUser(userName, password));
    Assert.AreEqual(handler.UserID, 5);
    Mock.Assert(service);
}

If the ValidateUser method is never called, the above test will fail with the message:

Telerik.JustMock.MockAssertionException : Expected call on the mock should occur exactly 1, but it was called 0 time(s).

JustMock actually provides the occurrence checking capability with loose mocks.  But to fully validate the behavior of a mocked object, you must use what is known as a strict mock.  Remember that methods not specifically arranged with a loose mock will simply return the default value? It is better to have an exception thrown, causing the test to fail, if any method is called without being arranged.

To create a strict mock, you simply add the parameter Behavior.Strict to Mock.Create as demonstrated in the code snippet below.

ILoginService service = Mock.Create<ILoginService>(Behavior.Strict);

To show the different behavior of the different types of Mocks, let’s return to the version of the unhappy path test that didn’t include the arrangement.  If you change the call to Mock.Create to create a Strict Mock, and run the test again, you will get a failed test with the following message:

Telerik.JustMock.MockException : All calls on the mocking object should be arranged first.

This enables you to validate not only that what was expected to be called was called, but it also catches unwanted side effect calls that you didn’t realize were occurring.

Summary

When it comes to testing, you need to ensure you are thoroughly executing your line of business code. But you must also keep in mind that if there is too much friction to the process, it simply won’t happen. By using SOLID development practices and JustMock to handle the dependencies and behavior verification, a significant amount of testing friction disappears.

JustMock-forum-02-2012


About the Author

Mehfuz Hossain

works as the Technical Advisor in DevTools Division . He is passionate playing around with the latest bits. He has been a Microsoft MVP, author of OS projects like LinqExtender and LINQ to flickr and most recently lighter (nodejs + mongo blogging engine). Prior to working at Telerik , Mehfuz worked as a core member in many high volume web applications including Pageflakes that is acquired by Live Universe in 2008. He is a frequent blogger and was also a contributor and site developer at dotnetslackers.com.

@mehfuzh

Related Posts

Comments

Comments are disabled in preview mode.