Thursday, August 12, 2010

The Difference between Mocks and Stubs

First off, i'll write some definitions for better off understanding differences between mocks and stubs.

State-based Testing : State-based testing is also known as state verification. The purpose of it is to exercise method(s) of an class under test whether the method(s) worked correctly by asserting the expected state of the class. For this, fake objects which are called stubs are used.

Stub : Stub is actually a fake object which is used to imitate a real object in order to test some state verifications.

Behavioral Testing : Some people use interaction based testing or action-driven testing instead behavioral testing. For performing behavioral testing, we use mock object which is fake object like stub.

Mock : Mock is actually fake object which is used to fake the real domain object for behavioral testing. In contrast to stub object, mock object can fail.

I'll write an simple example to perceive the implications of differences between stub and mock objects. Following code sample shows the real domain code. Login() method in LoginManager class is used to check whether email and password matches. If matched, write log message and set IsSaved property to true.

Creating Real Domain Classes and Interfaces

   1:  public interface IUser
   2:  {
   3:      int Id { get; set; }
   4:      string Name { get; set; }
   5:      string Email { get; set; }
   6:      string Password { get; set; }
   7:  }
   8:   
   9:  public class User : IUser
  10:  {
  11:      public int Id { get; set; }
  12:      public string Name { get; set; }
  13:      public string Email { get; set; }
  14:      public string Password { get; set; }
  15:  }
  16:   
  17:  public interface IUserRepository
  18:  {
  19:      IUser GetUser(string email, string password);
  20:  }
  21:   
  22:  public interface ILogger
  23:  {
  24:      void Save(string message);
  25:      bool IsSaved { get; set; }
  26:  }
  27:   
  28:  public class LoginManager
  29:  {
  30:      private IUserRepository repository;
  31:      private ILogger logger;
  32:      public LoginManager(IUserRepository repository, ILogger logger)
  33:      {
  34:          this.repository = repository;
  35:          this.logger = logger;
  36:      }
  37:   
  38:      public void Login(string email, string password)
  39:      {
  40:          IUser user = this.repository.GetUser(email, password);
  41:          this.logger.Save(user.Name + " has been logged in");
  42:          this.logger.IsSaved = true;
  43:      }
  44:  }

Writing Unit Testing with Stub Object

First of all, we should decide what we test. We'll make state-based testing by checking the IsSaved property of the Logger class. I'll use Rhino Mocks which you can download from http://www.ayende.com/projects/rhino-mocks.aspx .

I'll follow the following steps to write test code:
  • Create instance of stub objects
  • Set expectations
  • Create a real domain object with stub objects
  • Assert it

   1:  [Test]
   2:  public void Login_EmailandPasswordIsCorrect_LogIsSaved()
   3:  {
   4:      // create stub objects
   5:      var repository = MockRepository.GenerateStub<IUserRepository>();
   6:      var logger = MockRepository.GenerateStub<ILogger>();
   7:   
   8:      // set expectations
   9:      repository.Stub(x => x.GetUser(Arg<string>.Is.Anything, 
  10:          Arg<string>.Is.Anything)).Return(new User());
  11:   
  12:      // create real domain object
  13:      LoginManager manager = new LoginManager(repository, logger);
  14:      manager .Login("test","password");
  15:   
  16:      // assert it
  17:      Assert.AreEqual(true, logger.IsSaved);
  18:  }
On line 5 and 6, I created two fake objects which are stubs called repository and logger.

On line 9, I used Stub method to set expectation with constraints. GetUser() method can only receive two string arguments and returns User object.

On line 13, I created an instance of a class which is under test and passed two stub objects into its constructor. Then i invoked Login() method with "dummy" arguments. If Login() method worked correctly, IsSaved property of Logger class must be set "true".

Finally, line 17th, i asserted that value of IsSaved property must be true.

It's nice to say that, I can test the method before implementing production code. Even if i haven't build Logger and UserRepository classes. After testing all cases, if tests pass, there is nothing to stop me to write production code.

Writing Unit Testing with Mock Object

I want to test behavioral verification. Therefore I'll use mock object. My purpose is to be sure that Save() method in Logger class is invoked with correct arguments.


   1:  [Test]
   2:  public void Login_EmailandPasswordIsCorrect_LogSaveMethodRunsCorrectly()
   3:  {
   4:      // create stub and mock objects
   5:      var repository = MockRepository.GenerateStub<IUserRepository>();
   6:      var user = MockRepository.GenerateMock<IUser>();
   7:      var logger = MockRepository.GenerateMock<ILogger>();
   8:   
   9:      // set expectations
  10:      user.Expect(x => x.Id).Return(1);
  11:      user.Expect(x => x.Name).Return("serkan");
  12:      user.Expect(x => x.Email).Return("test@technolatte.net");
  13:      user.Expect(x => x.Password).Return("123456");
  14:   
  15:      repository.Stub(x => x.GetUser(Arg<string>.Is.Anything, 
  16:          Arg<string>.Is.Anything)).Return(user);
  17:      logger.Expect(x => x.Save("serkan has been logged in"));
  18:   
  19:      // create real domain object
  20:      LoginManager manager = new LoginManager(repository, logger);
  21:      manager.Login(string.Empty, string.Empty);
  22:   
  23:      // verify mock object
  24:      logger.VerifyAllExpectations();
  25:  }

Line 6th and 7th, I created two mock objects and line 5th i created one stub object.

I set mock objects with expected values.

On line 17, I used Expect() method to assume that Save() method of Logger class would be invoked with string argument which is equal to "serkan has been logged in".

Line 24th, i verified all expectations.

It's useless and less efficiency to write unit testing without knowing the differences between mock and stub objects. .

  • Stub can't fail test but mocks can. 
  • Stub is used for state-based testing, mock is used for behavioral testing.
  • Mock objects keep the history of communication which will be verified later.
  • The mock object is covered by a specification of expectation for the calls it’s expected to receive. Stub contains of preserved responses to requests that are sent during the test process.

Every fake object you create is stub by default unless if you want to test it. Otherwise it's called mock. If you verify calls against it, it's a mock, otherwise it's a stub.

Finally, I suggest the article written by Martin Fowler on his own web site about distinction of mock and stub to understand better what the differences are.

Friday, August 6, 2010

How to Create Fake Objects Manually

In order to understand xUnit frameworks, it'd be nice starting point to write your own fake objects to help yourself  write your test code by using "isolation framework". I said "fake" objects instead of mock or stub. Because your fake objects can act as a stub or mock depends on context of the unit test. I mean, same fake object can be stub or mock.

Every unit test you will write you don't need to use mock or stub. You can create instance of a object that is under test code than assert the method with expected and current result.

But sometimes, you need to touch external tools, devices or services in your production code. For instance you need to test sending email or changing speaker volume. Although it's possible to use concrete object to test your code, this way is not recommended. Because, it's take too much to write your test code and it's easily fragile. The point is you are able to test your code without touching external environment such as web services, email server or 3rd party tools.

Here is our requirements:
You are able to change the speaker volume if value is greater than zero. 

Let's make a simple class structure which we will test. We have a DeviceManager class which handle all devices such as speaker or microphone. Speaker class which is inherited by ISpeaker interface is used to handle volume of speaker.

   1:  public class DeviceManager
   2:  {
   3:      private ISpeaker speaker;
   4:   
   5:      public DeviceManager(ISpeaker speaker)
   6:      {
   7:          this.speaker = speaker;    
   8:      }
   9:   
  10:      public void ChangeSpeakerVolume(int volume)
  11:      {
  12:          if (volume > 0)
  13:          {
  14:              speaker.ChangeVolume(volume);
  15:          }
  16:      }
  17:  }
  18:   
  19:  public interface ISpeaker
  20:  {
  21:      void ChangeVolume(int volume);
  22:  }
  23:   
  24:  public class Speaker : ISpeaker
  25:  {
  26:      public void ChangeVolume(int volume)
  27:      {
  28:          // we don't care how to touch
  29:          // the hardware of your computer and change the volume
  30:      }
  31:  }

Before writing test code, there are some widely accepted rules to make test codes more readable and maintainable. These rules are about naming conventions.

For each test method's name should give an idea to developers what is tested. So, test method should contains of :
  • Method name, you want to test , in under test class
  • The conditions of testing
  • Expected behavior
[MethodName]_[Conditions]_[ExpectedBehavior]

   1:  using NUnit.Framework;
   2:   
   3:  [TestFixture]
   4:  public class DeviceManagerTests
   5:  {
   6:  [Test]
   7:  public void ChangeSpeakerVolume_VolumeIsGreaterThanZero_Success()
   8:  {
   9:      // create our fake object
  10:      FakeSpeaker fakeSpeaker = new FakeSpeaker();
  11:   
  12:      // here our fake object acts as a mock object.
  13:      // because our test aim is behavioral test. 
  14:      // i mean, we want to be sure that
  15:      // ChangeSpeakerVolume method is performed.
  16:   
  17:      int expectedVolume = 50;
  18:   
  19:      // create instance of under test class
  20:      DeviceManager device = new DeviceManager(fakeSpeaker);
  21:      device.ChangeSpeakerVolume(expectedVolume);
  22:   
  23:      Assert.AreEqual(expectedVolume, fakeSpeaker.LatestVolume);
  24:      // assert is performed on the fake object which is mock.
  25:  }
  26:  }
  27:   
  28:  public class FakeSpeaker : ISpeaker
  29:  {
  30:  public int LatestVolume;
  31:   
  32:  public void ChangeVolume(int volume)
  33:  {
  34:      this.LatestVolume = volume;
  35:  }

As you see, on 28th line, i created FakeSpeaker class inherited by ISpeaker. In this ChangeVolume method (on 32nd line), i didn't write code to touch speaker hardware and change its volume. Because, my aim is whether ChangeVolume method in DeviceManager class is invoked I added LatestVolume variable (on 30th line) as public in our FakeSpeaker class to check ChangeVolume method in FakeSpeker class is called. If ChangeVolume method is performed successfully, i set the volume to LatestVolume variable.

Steps are really easy :

  • Create a fake object (on 10th line)
  • Set expectations (on 17th line)
  • Create instance of under test class and call method under test (on 20th and 21st line)
  • Assert it by passing expected and actual value (on 23rd line)

Although you can use test frameworks to create fake objects, sometimes it's handy to create your own fake classes for simple projects. If you know how to create fake objects manually, you can have better comprehending when you start to use tool which is isolation framework to create mock and stub objects. I highly recommend using isolation framework to isolate the unit under tests from anything around it.