Unit Tests and Mocks libraries Guillaume Carre May 2008 XP Day Paris Certified ScrumMaster
Agenda Introduction Mocks Unit Testing and Mock objects Automatic generation of mock objets: EasyMock code examples Mocks libraries comparison Mocks and Test Driven Development Conclusion Links Questions
Introduction Writing defect-free software is exceedingly difficult Automated verification of software behavior is one of the biggest advances in development methods in the last few decades The sooner we get feedback, the more quickly we can react Tests can help understand the “System Under Test “ (SUT) Without unit tests, we can’t refactor code Unit tests are the backbone of Agile Methodologies
Unit Tests  / Integration Tests Unit Test: code tested in isolation Unit Tests don’t see the big picture, we need to validate that all pieces of code work together Of course Integration and Functional Tests are mandatory, even with good Unit Tests
Unit Tests: test code in isolation Definition :  a unit test exercises a single class in isolation of all others Test one feature at a time: We need to know exactly what we are testing We need to know exactly where problems are Test code must be readable and clear To test code in isolation, collaborators are replaced by dummy objects, « stubs » or « mocks »
Unit tests and Mock objects Mocks objects are dummy implementations of collaborators Simpler than the real code Mocks are not stubs Stubs check state Mocks check behaviour Hand crafted stubs can be to hard to write and to maintain
Benefits from using Mock objects Tests are specification, use of Mock objects helps in having a good description of the SUT behaviour Common format for unit tests Code ends up simple and clean with a better design Tests run faster Design for testability
Code example Simple cart and stock application CartManager  is the System Under Test (SUT) ProductDAO  is the collaborator of CartManager
Mocks libraries No need to write mocks at all Mocks are created dynamically at test run time 3 phases: Mock  setup : parameter expectations, return values, call counts, thrown exceptions Mock  replay  to record the behaviour Mock  verification
Without mock objects
With mock objects (EasyMock)
Usage 1/3 Expect, return and replay expect (productDAOMock.isInStock( PRODUCT_ID , 20)) .andReturn( true ); replay( productDAOMock ); Verify behavior verify( productDAOMock ); AssertionError is thrown if an expectation has not been described java.lang.AssertionError Unexpected method call   removeFromStock(1L, 20) AssertionError is thrown if an expectation has been described but not fullfilled java.lang.AssertionError removeFromStock(1L, 20): expected: 1, actual: 0
Usage 2/3 Explicit number of calls If isInStock is called 3 times, instead of productDAOMock.isInStock( PRODUCT_ID , 20)) ; productDAOMock.isInStock( PRODUCT_ID , 20)) ; productDAOMock.isInStock( PRODUCT_ID , 20)) ; One can write: productDAOMock.isInStock( PRODUCT_ID , 20)) ; expectLastCall().times(3); Throwing an exception expect( productDAOMock.isInStock( PRODUCT_ID , 20) ).andThrow( new ProductDAOException() );
Usage 3/3 Strict mocks -> With strict mocks order of methods calls is checked ProductDAO productDAO =  createStrictMock (ProductDAO.class); Argument matchers -> used if mock method parameters are instanciated from inside the tested method expect (productDAOMock.isInStock( isA(Long.class) , isA(Integer.class))) .andReturn( true ); Other argument matchers:  isNull(), eq(X value), anyObject(), startsWith(String prefix) , etc…
Mocks libraries roundup JMock 2: Refactorable test code Promotes the use of anonymous classes: test code is difficult to read JMock 1: First mock library Treat methods as Strings: test code is not refactorable EasyMock: Best syntax out there: refactorable AND readable Used in Spring framework for unit tests Mockito: The new kid on the block "run – verify" pattern (no "record")
Mocks & TDD Classical TDD: use real objects if possible, and a double if not possible Coding manual stubs can take more time than using mocks Mockist TDD: will always use a mock for any collaborator Classical TDDers code “dummy” collaborators, to make the test green, and then implement collaborators when needed. Using mocks for collaborators can seem awkward for a classical TDDer Usually TDDers prefer the Classical approach Give the Mockist approach a try, and choose the one you prefer!
Cons Debugging using generated mocks can be more difficult than with hand written mocks A risk is to develop too much specified unit tests, hence fragile tests, that will break on each SUT minor modification
Links http://www.mockobjects.com http://www.martinfowler.com/articles/mocksArentStubs.html http://www.jmock.org http://www.easymock.org http://code.google.com/p/mockito
Conclusion In our experience, mocks libraries save time, and help in writing simple, consistent and predictable mocks Developing with mock objects has beneficial effects on the team members coding style (coding to Interfaces, Dependency Injection, etc.) Integration testing and Functional testing are of course still necessary, even with good unit tests
Questions ?

Xp Day 080506 Unit Tests And Mocks

  • 1.
    Unit Tests andMocks libraries Guillaume Carre May 2008 XP Day Paris Certified ScrumMaster
  • 2.
    Agenda Introduction MocksUnit Testing and Mock objects Automatic generation of mock objets: EasyMock code examples Mocks libraries comparison Mocks and Test Driven Development Conclusion Links Questions
  • 3.
    Introduction Writing defect-freesoftware is exceedingly difficult Automated verification of software behavior is one of the biggest advances in development methods in the last few decades The sooner we get feedback, the more quickly we can react Tests can help understand the “System Under Test “ (SUT) Without unit tests, we can’t refactor code Unit tests are the backbone of Agile Methodologies
  • 4.
    Unit Tests / Integration Tests Unit Test: code tested in isolation Unit Tests don’t see the big picture, we need to validate that all pieces of code work together Of course Integration and Functional Tests are mandatory, even with good Unit Tests
  • 5.
    Unit Tests: testcode in isolation Definition : a unit test exercises a single class in isolation of all others Test one feature at a time: We need to know exactly what we are testing We need to know exactly where problems are Test code must be readable and clear To test code in isolation, collaborators are replaced by dummy objects, « stubs » or « mocks »
  • 6.
    Unit tests andMock objects Mocks objects are dummy implementations of collaborators Simpler than the real code Mocks are not stubs Stubs check state Mocks check behaviour Hand crafted stubs can be to hard to write and to maintain
  • 7.
    Benefits from usingMock objects Tests are specification, use of Mock objects helps in having a good description of the SUT behaviour Common format for unit tests Code ends up simple and clean with a better design Tests run faster Design for testability
  • 8.
    Code example Simplecart and stock application CartManager is the System Under Test (SUT) ProductDAO is the collaborator of CartManager
  • 9.
    Mocks libraries Noneed to write mocks at all Mocks are created dynamically at test run time 3 phases: Mock setup : parameter expectations, return values, call counts, thrown exceptions Mock replay to record the behaviour Mock verification
  • 10.
  • 11.
  • 12.
    Usage 1/3 Expect,return and replay expect (productDAOMock.isInStock( PRODUCT_ID , 20)) .andReturn( true ); replay( productDAOMock ); Verify behavior verify( productDAOMock ); AssertionError is thrown if an expectation has not been described java.lang.AssertionError Unexpected method call removeFromStock(1L, 20) AssertionError is thrown if an expectation has been described but not fullfilled java.lang.AssertionError removeFromStock(1L, 20): expected: 1, actual: 0
  • 13.
    Usage 2/3 Explicitnumber of calls If isInStock is called 3 times, instead of productDAOMock.isInStock( PRODUCT_ID , 20)) ; productDAOMock.isInStock( PRODUCT_ID , 20)) ; productDAOMock.isInStock( PRODUCT_ID , 20)) ; One can write: productDAOMock.isInStock( PRODUCT_ID , 20)) ; expectLastCall().times(3); Throwing an exception expect( productDAOMock.isInStock( PRODUCT_ID , 20) ).andThrow( new ProductDAOException() );
  • 14.
    Usage 3/3 Strictmocks -> With strict mocks order of methods calls is checked ProductDAO productDAO = createStrictMock (ProductDAO.class); Argument matchers -> used if mock method parameters are instanciated from inside the tested method expect (productDAOMock.isInStock( isA(Long.class) , isA(Integer.class))) .andReturn( true ); Other argument matchers: isNull(), eq(X value), anyObject(), startsWith(String prefix) , etc…
  • 15.
    Mocks libraries roundupJMock 2: Refactorable test code Promotes the use of anonymous classes: test code is difficult to read JMock 1: First mock library Treat methods as Strings: test code is not refactorable EasyMock: Best syntax out there: refactorable AND readable Used in Spring framework for unit tests Mockito: The new kid on the block "run – verify" pattern (no "record")
  • 16.
    Mocks & TDDClassical TDD: use real objects if possible, and a double if not possible Coding manual stubs can take more time than using mocks Mockist TDD: will always use a mock for any collaborator Classical TDDers code “dummy” collaborators, to make the test green, and then implement collaborators when needed. Using mocks for collaborators can seem awkward for a classical TDDer Usually TDDers prefer the Classical approach Give the Mockist approach a try, and choose the one you prefer!
  • 17.
    Cons Debugging usinggenerated mocks can be more difficult than with hand written mocks A risk is to develop too much specified unit tests, hence fragile tests, that will break on each SUT minor modification
  • 18.
    Links http://www.mockobjects.com http://www.martinfowler.com/articles/mocksArentStubs.htmlhttp://www.jmock.org http://www.easymock.org http://code.google.com/p/mockito
  • 19.
    Conclusion In ourexperience, mocks libraries save time, and help in writing simple, consistent and predictable mocks Developing with mock objects has beneficial effects on the team members coding style (coding to Interfaces, Dependency Injection, etc.) Integration testing and Functional testing are of course still necessary, even with good unit tests
  • 20.