Mock Objects:
                               From Concept to Code
                                           Rob Myers
                                               for
                                  Agile Development Practices
                                              East
                                          07 Nov 2012




7 November 2012   © Agile Institute 2012                    1
7 November 2012   © Agile Institute 2012   2
difficult to set up

A database.
A complex object graph.

                                                         Stock
                                                 Fund
                                   Account               Stock
                                                 Stock
                   Investor
                                                         Stock

                                   Account       Fund    Stock

                                                         Stock

7 November 2012         © Agile Institute 2012              3
expensive to test against*



The production database.
Your personal credit card.
A “password changed” confirmation
 sent to the CEO of a large
 investment firm.

     * Each of these “Career-Limiting Moves” was actually witnessed by me
                          during the “dot-COM” era.



7 November 2012               © Agile Institute 2012                        4
chaotic




                  The database.
                  A randomizer.
                   The weather.




7 November 2012          © Agile Institute 2012   5
…slow…


The database.
The network.
The filesystem.
Interplanetary radio signals?!




7 November 2012    © Agile Institute 2012   6
Fast!
                  Reliable!




7 November 2012     © Agile Institute 2012   7
7 November 2012   © Agile Institute 2012   8
from Martin Fowler et al

• Fakes provide reasonable facsimiles of the real
  thing, but are not quite robust enough for
  production (e.g., an in-memory database).

• Stubs provide scripted responses to calls. They
  may also record information about calls made
  during the test.

• Mocks are programmed by tests, creating
  expectations for potentially the entire
  specification of a call, including arguments.

7 November 2012      © Agile Institute 2012         9
classicists v. mockists

Hand-Crafted Mocks (“Stubs”)
    + Simple & familiar.
    + Black-box.
    + Can do something clever (e.g., throw exception for
      a special argument), or hold state (e.g., collect a
      buffered result for an assertion).
    - Can get too complex if reused everywhere.

Dynamic Mocking Tools (“Mocks”)
    + Great for interactions/protocols.
    + Can be used in numerous variations or scenarios.
    - White-box: Can be too explicit about
      implementation.



7 November 2012          © Agile Institute 2012          10
never an absolutist




7 November 2012        © Agile Institute 2012   11
Investments
     Earthbound




7 November 2012    © Agile Institute 2012   12
Write StockQuote class
Create a StockQuote for the current price
 of a LunEx stock.

Quote total should reflect our 2%
 commission on all LunEx transactions, plus
 the flat LunEx communication surcharge of
 $10.

Be sure we invoke LunEx once per quote,
 as they charge $0.05 per invocation!

  7 November 2012      © Agile Institute 2012   13
DATABASE




      StockQuote         LunExServices

+ double total()   + double currentPrice(
                       String symbol
                     )


7 November 2012    © Agile Institute 2012         14
Testing with a Mock


                       StockQuote                         LunExServices

                    + double total()                  + double currentPrice(
                                                          String symbol
                                                        )




                                                        MockLunExServices
  StockQuoteTests
                                                      + double currentPrice(
+ totalWorksRight()                                       String symbol
                               defines
                                                        )




 7 November 2012             © Agile Institute 2012                         15
Write StockQuote class
Create a StockQuote for the current price
 of a LunEx stock.

Quote total should reflect our 2%
 commission on all LunEx transactions, plus
 the flat LunEx communication surcharge of
 $10.

Be sure we invoke LunEx once per quote,
 as they charge $0.05 per invocation!

  7 November 2012      © Agile Institute 2012   16
a test

@Test
public void totalCalculatesCorrectly() {
   // given
   LunExServices myService =
       Mockito.mock(LunExServices.class);
   Mockito.when(myService.currentPrice("HE3"))
    .thenReturn(12.00);

    StockQuote quote = new StockQuote("HE3", 100, myService);

    // when
    double total = quote.total();
    // then
    Assert.assertEquals(1234.00, total, 0.00001);
}

7 November 2012         © Agile Institute 2012            17
just enough to compile & fail

package earthboundInvestments;

import lunEx.LunExServices;

public class StockQuote {
   public StockQuote(String symbol,
       int numberOfShares,
       LunExServices service) {
   }

    public double total() {
        return 0;
    }
}


7 November 2012         © Agile Institute 2012   18
7 November 2012   © Agile Institute 2012   19
“Obvious Implementation”

public class StockQuote {
   private final double total;
   public StockQuote(String symbol,
              int numberOfShares,
              LunExServices service) {
       total = service.currentPrice(symbol) * numberOfShares
              * 1.02 + 10.00;
   }

    public double total() {
        return total;
    }
}




7 November 2012         © Agile Institute 2012           20
7 November 2012   © Agile Institute 2012   21
what else?
@Test
public void totalCalculatesCorrectly() {
   // given
   LunExServices myService =
       Mockito.mock(LunExServices.class);
   Mockito.when(myService.currentPrice("HE3"))
    .thenReturn(12.00);

    StockQuote quote = new StockQuote("HE3", 100, myService);

    // when
    double total = quote.total();
    // then
    Assert.assertEquals(1234.00, total, 0.00001);
    Mockito.verify(myService, Mockito.times(1))
               .currentPrice("HE3");
}
7 November 2012         © Agile Institute 2012            22
test using hand-crafted mock
@Test
public void totalCalculatesCorrectly_usingHandCraftedMock() {
    // given
    MockLunExServices myService = new MockLunExServices(12.00);

    StockQuote quote = new StockQuote("HE3", 100, myService);

    // when
    double total = quote.total();

    // then
    Assert.assertEquals(1234.00, total, 0.00001);
    Assert.assertTrue(myService.wasCalledOnceAndOnlyOnce());
}



7 November 2012        © Agile Institute 2012             23
hand-crafted mock
 public class MockLunExServices extends LunExServices {
    private double valueToReturn;
    private int callCount = 0;

     public MockLunExServices(double valueToReturn) {
         this.valueToReturn = valueToReturn;
     }
     @Override
     public double currentPrice(String symbol) {
         callCount++;
         return valueToReturn;
     }

     public boolean wasCalledOnceAndOnlyOnce() {
         return callCount == 1;
     }
 }
7 November 2012         © Agile Institute 2012            24
Summary:

      1.   Agile: Good!
      2.   “Agilist’s Dilemma”: Very bad.
      3.   TDD: Great!
      4.   Slow, non-deterministic tests: Bad.
      5.   Mocks: Good.
      6.   “Never an Absolutist!”


7 November 2012       © Agile Institute 2012     25
7 November 2012   © Agile Institute 2012   26
Rob.Myers@agileInstitute.com

         http://PowersOfTwo.agileInstitute.com/

         @agilecoach




7 November 2012        © Agile Institute 2012     27

Mock Objects from Concept to Code

  • 1.
    Mock Objects: From Concept to Code Rob Myers for Agile Development Practices East 07 Nov 2012 7 November 2012 © Agile Institute 2012 1
  • 2.
    7 November 2012 © Agile Institute 2012 2
  • 3.
    difficult to setup A database. A complex object graph. Stock Fund Account Stock Stock Investor Stock Account Fund Stock Stock 7 November 2012 © Agile Institute 2012 3
  • 4.
    expensive to testagainst* The production database. Your personal credit card. A “password changed” confirmation sent to the CEO of a large investment firm. * Each of these “Career-Limiting Moves” was actually witnessed by me during the “dot-COM” era. 7 November 2012 © Agile Institute 2012 4
  • 5.
    chaotic The database. A randomizer. The weather. 7 November 2012 © Agile Institute 2012 5
  • 6.
    …slow… The database. The network. Thefilesystem. Interplanetary radio signals?! 7 November 2012 © Agile Institute 2012 6
  • 7.
    Fast! Reliable! 7 November 2012 © Agile Institute 2012 7
  • 8.
    7 November 2012 © Agile Institute 2012 8
  • 9.
    from Martin Fowleret al • Fakes provide reasonable facsimiles of the real thing, but are not quite robust enough for production (e.g., an in-memory database). • Stubs provide scripted responses to calls. They may also record information about calls made during the test. • Mocks are programmed by tests, creating expectations for potentially the entire specification of a call, including arguments. 7 November 2012 © Agile Institute 2012 9
  • 10.
    classicists v. mockists Hand-CraftedMocks (“Stubs”) + Simple & familiar. + Black-box. + Can do something clever (e.g., throw exception for a special argument), or hold state (e.g., collect a buffered result for an assertion). - Can get too complex if reused everywhere. Dynamic Mocking Tools (“Mocks”) + Great for interactions/protocols. + Can be used in numerous variations or scenarios. - White-box: Can be too explicit about implementation. 7 November 2012 © Agile Institute 2012 10
  • 11.
    never an absolutist 7November 2012 © Agile Institute 2012 11
  • 12.
    Investments Earthbound 7 November 2012 © Agile Institute 2012 12
  • 13.
    Write StockQuote class Createa StockQuote for the current price of a LunEx stock. Quote total should reflect our 2% commission on all LunEx transactions, plus the flat LunEx communication surcharge of $10. Be sure we invoke LunEx once per quote, as they charge $0.05 per invocation! 7 November 2012 © Agile Institute 2012 13
  • 14.
    DATABASE StockQuote LunExServices + double total() + double currentPrice( String symbol ) 7 November 2012 © Agile Institute 2012 14
  • 15.
    Testing with aMock StockQuote LunExServices + double total() + double currentPrice( String symbol ) MockLunExServices StockQuoteTests + double currentPrice( + totalWorksRight() String symbol defines ) 7 November 2012 © Agile Institute 2012 15
  • 16.
    Write StockQuote class Createa StockQuote for the current price of a LunEx stock. Quote total should reflect our 2% commission on all LunEx transactions, plus the flat LunEx communication surcharge of $10. Be sure we invoke LunEx once per quote, as they charge $0.05 per invocation! 7 November 2012 © Agile Institute 2012 16
  • 17.
    a test @Test public voidtotalCalculatesCorrectly() { // given LunExServices myService = Mockito.mock(LunExServices.class); Mockito.when(myService.currentPrice("HE3")) .thenReturn(12.00); StockQuote quote = new StockQuote("HE3", 100, myService); // when double total = quote.total(); // then Assert.assertEquals(1234.00, total, 0.00001); } 7 November 2012 © Agile Institute 2012 17
  • 18.
    just enough tocompile & fail package earthboundInvestments; import lunEx.LunExServices; public class StockQuote { public StockQuote(String symbol, int numberOfShares, LunExServices service) { } public double total() { return 0; } } 7 November 2012 © Agile Institute 2012 18
  • 19.
    7 November 2012 © Agile Institute 2012 19
  • 20.
    “Obvious Implementation” public classStockQuote { private final double total; public StockQuote(String symbol, int numberOfShares, LunExServices service) { total = service.currentPrice(symbol) * numberOfShares * 1.02 + 10.00; } public double total() { return total; } } 7 November 2012 © Agile Institute 2012 20
  • 21.
    7 November 2012 © Agile Institute 2012 21
  • 22.
    what else? @Test public voidtotalCalculatesCorrectly() { // given LunExServices myService = Mockito.mock(LunExServices.class); Mockito.when(myService.currentPrice("HE3")) .thenReturn(12.00); StockQuote quote = new StockQuote("HE3", 100, myService); // when double total = quote.total(); // then Assert.assertEquals(1234.00, total, 0.00001); Mockito.verify(myService, Mockito.times(1)) .currentPrice("HE3"); } 7 November 2012 © Agile Institute 2012 22
  • 23.
    test using hand-craftedmock @Test public void totalCalculatesCorrectly_usingHandCraftedMock() { // given MockLunExServices myService = new MockLunExServices(12.00); StockQuote quote = new StockQuote("HE3", 100, myService); // when double total = quote.total(); // then Assert.assertEquals(1234.00, total, 0.00001); Assert.assertTrue(myService.wasCalledOnceAndOnlyOnce()); } 7 November 2012 © Agile Institute 2012 23
  • 24.
    hand-crafted mock publicclass MockLunExServices extends LunExServices { private double valueToReturn; private int callCount = 0; public MockLunExServices(double valueToReturn) { this.valueToReturn = valueToReturn; } @Override public double currentPrice(String symbol) { callCount++; return valueToReturn; } public boolean wasCalledOnceAndOnlyOnce() { return callCount == 1; } } 7 November 2012 © Agile Institute 2012 24
  • 25.
    Summary: 1. Agile: Good! 2. “Agilist’s Dilemma”: Very bad. 3. TDD: Great! 4. Slow, non-deterministic tests: Bad. 5. Mocks: Good. 6. “Never an Absolutist!” 7 November 2012 © Agile Institute 2012 25
  • 26.
    7 November 2012 © Agile Institute 2012 26
  • 27.
    Rob.Myers@agileInstitute.com http://PowersOfTwo.agileInstitute.com/ @agilecoach 7 November 2012 © Agile Institute 2012 27

Editor's Notes

  • #2 Agile has dirty little secret: Iteratively slower and slower…
  • #3 Comprehensive suite of repeatable (automated) regression tests eases the Agilist’s Dilemma…
  • #5 What else? <before advancing>
  • #7 What do these have in common…?
  • #8 Most teams find it challenging to keep them fast and deterministic over time.
  • #11  Hand-crafted mocks:+ In C++, in/out parameters perhaps easier to handle.
  • #28 Thank you!