TDD with mocks and spies



    Some testing tools like Moq (with MockBehavior.Strict), NMock, JMock and Rhino Mocks fluent and record/playback syntax use mocks.

    Other testing tools like Moq (with Verify), Mockito and Rhino Mocks AAA syntax use spies.


Here I will note down the characteristics of both. Let start with the differences.



Spies allow to assert the expectations after the invocation of the method being tested, while mocks (we are talking abou strict mocks) require to set expectations before the target method invocation.
Because of it someone finds the test written with spies more readable, while someone else finds easier to write tests with mocks because that way is more similar to the Design by Contract way of thinking.



Another key difference is that spies stub values by default while mocks fail when implementation invokes a method that hasn't been specified in the test.
Because of it spies are easier to use than mocks with legacy code and existing code with deep design problems. While mocks surface early design problems,
when listening to the tests, and they encourage to fix design problems early, before they grow.

So
mocks are effective when testing new code and code with design problems you are willing and capable to fix.  On the other hand, spies fail to surface design problems while mocks when used to tests legacy code face all the design problems that obstacle testing. When testing with mocks, design problems needs to be properly addressed, ignoring them or trying to work around them lead to brittle tests.




A characteristic of spies is that they checks for direct output so tests with spices make a clear distinction between input and output.
A characteristic of mocks is that they aid to design in term of protocols and message passing with "tell, don't ask" OO style.




There is some debate between spies versus strict mocks based on some poor code-bases observed in teams using one ore the other. This is not a very relevant point: no technique can survive inadequately trained developers.


If you sees TDD mainly as a design method and you design with a message passing OO style probably you gonna prefer to use mocks and learn the tests smells and listen to the tests. If you sees TDD mainly as test practice probably you gonna prefer to use spies.


Those notes are collected from the Growing object oriented software group.




Edit, 7 Jan 2011, added code sample:

Here is the example of a test with a mock, the expectation is asserted at line 8 on a strict mock (fails for calls not expected).

   1:  [Test]
   2:  public void When_user_forget_password_will_send_notification()
   3:  {
   4:      var userRepository = MockRepository.GenerateStub<IUserRepository>();
   5:      var notificationSender = MockRepository.GenerateMock<INotificationSender>();
   6:   
   7:      userRepository.Stub(x => x.GetUserById(123)).Return(new User { Id = 123, Name = "luka" });
   8:      notificationSender.Expect(x => x.Send(null));
   9:   
  10:      new LoginController(userRepository, notificationSender).ForgotMyPassword(123);
  11:   
  12:      notificationSender.VerifyAllExpectations();
  13:  }


Here is the example of a test with a spy, the expectation is asserted at line 11 on a stub (all calls are stubbed by default).

   1:  [Test]
   2:  public void When_user_forget_password_will_send_notification()
   3:  {
   4:      var userRepository = MockRepository.GenerateStub<IUserRepository>();
   5:      var notificationSender = MockRepository.GenerateStub<INotificationSender>();
   6:   
   7:      userRepository.Stub(x => x.GetUserById(123)).Return(new User { Id = 123, Name = "luKa" });
   8:   
   9:      new LoginController(userRepository, notificationSender).ForgotMyPassword(123);
  10:   
  11:      notificationSender.AssertWasCalled(x => x.Send(null));
  12:  }


And here an example in Ruby.



Print | posted @ giovedì 6 gennaio 2011 06:37

Comments on this entry:

Gravatar # re: TDD with mocks and spies
by Carlos Ble at 04/12/2011 03:34

Good article Luca!
Just wanted to point out that Moq uses spies, it is pretty similar to Mockito :-)

Cheers mate
Comments have been closed on this topic.