Search code examples
javatestingmockingmockitojmock

Does mockito have an equivalent idiom to jMock's States?


The book Growing Object Oriented Software gives several examples in jMock where the state is made explicit without exposing it through an API. I really like this idea. Is there a way to do this in Mockito?

Here's one example from the book

public class SniperLauncherTest {
   private final States auctionState = context.states("auction state")
                                              .startsAs("not joined");

   @Test public void addsNewSniperToCollectorAndThenJoinsAuction() {
     final String itemId = "item 123";
     context.checking(new Expectations() {{
       allowing(auctionHouse).auctionFor(itemId); will(returnValue(auction));

       oneOf(sniperCollector).addSniper(with(sniperForItem(item)));
                                   when(auctionState.is("not joined"));      
       oneOf(auction).addAuctionEventListener(with(sniperForItem(itemId)));
                                   when(auctionState.is("not joined"));
       one(auction).join(); then(auctionState.is("joined"));
     }});

     launcher.joinAuction(itemId);
   }
}

Solution

  • I used a spy for the self same exercise:

    http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#13

    I changed my SniperListener mock into a spy thus:

    private final SniperListener sniperListenerSpy = spy(new SniperListenerStub());
    private final AuctionSniper sniper = new AuctionSniper(auction, sniperListenerSpy);
    

    And also created a stubbed implementation of SniperListener:

    private class SniperListenerStub implements SniperListener {
        @Override
        public void sniperLost() {
        }
    
        @Override
        public void sniperBidding() {
            sniperState = SniperState.bidding;
        }
    
        @Override
        public void sniperWinning() {
        }
    }
    

    The book uses JMock's "States", but I used a nested enum instead:

    private SniperState sniperState = SniperState.idle;
    
    private enum SniperState {
        idle, winning, bidding
    }
    

    You then have to use regular JUnit asserts to test for the state:

    @Test
    public void reportsLostIfAuctionClosesWhenBidding() {
        sniper.currentPrice(123, 45, PriceSource.FromOtherBidder);
        sniper.auctionClosed();
        verify(sniperListenerSpy, atLeastOnce()).sniperLost();
        assertEquals(SniperState.bidding, sniperState);
    }