Very random; I haven't been taking too many Mockito notes though I work very intensively with it.
import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.stubbing.Answer; import org.mockito.ArgumentCaptor; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock;
import static org.mockito.Mockito.any; import static org.mockito.Mockito.when; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyObject; import static org.mockito.AdditionalAnswers.returnsFirstArg; import static org.mockito.AdditionalAnswers.returnsSecondArg;
Highlighted are lines with specifically Mockito constructs.
@Test public void testSendWithStringProperties() throws Exception { AmazonSQSClient awsClient = Mockito.mock( AmazonSQSClient.class ); SqsOperations sqsOperations = setup(); // this makes send() encode properties with the message body... Message message = setupMessageWithStringProperties(); message.setId( null ); when( awsClient.sendMessage( any( SendMessageRequest.class ) ) ).thenReturn( sendMessageResult( message ) ); ArgumentCaptor< SendMessageRequest > argument = ArgumentCaptor.forClass( SendMessageRequest.class ); String messageId = sqsOperations.send( message ); assertNotNull( messageId ); verify( awsClient ).sendMessage( argument.capture() ); String url = argument.getValue().getQueueUrl(); String body = argument.getValue().getMessageBody(); // now verify what was passed as SendMessageRequest, but... assertEquals( url, AWS_QUEUE_URL ); // ...the message body has one or more encoded properties inside, so check that too assertEquals( body, BODY_SPROPS ); }
Use of Mockito.mock() to create a mock. Use of when(), ArgumentCaptor and verify().
@Test public void testMarkInProgress() { // mock out the SUT's guts with a messenger and (minimal) behavior of returning our fake message... messenger = Mockito.mock( Messenger.class ); when( messenger.createMessage()).thenReturn( new MessageImpl() ); doAnswer( new Answer< Void >() { public Void answer( InvocationOnMock invocation ) { Object[] args = invocation.getArguments(); return null; } } ).when( messenger ).send( any( QueueId.class ), any( Message.class ) ); ArgumentCaptor< Message > argument = ArgumentCaptor.forClass( Message.class ); fixture.markInProgress( osId, Type.FHID ); verify( messenger ).send(any( QueueId.class ), argument.capture() ); assertNotNull( argument.getValue().getProperty( FHID_PROPERTY ) ); }
@Test public void testMarkInProgress() { // 1. Mock out the fixture's guts with a messenger messenger = Mockito.mock( Messenger.class ); // 1bis. Make createMessage() do what it normally would when( messenger.createMessage() ).thenReturn( new MessageImpl() ); // 2. Set up a fixture for the class under test fixture = new ReservationMessageFactoryImpl(); fixture.setConfigSection( "pubResvMessage" ); PropertySet ps = PropertyManager.getPropertySet( fixture.getConfigSection() ); ps.setVolatileProperty( "queues", "ACME;ACMETESTS" ); fixture.setMsgStore( messenger ); // 2bis. We'll need two queues (remember that) List<String > queueList = new ArrayList<>( 1 ); queueList.add( "ACME_RESV" ); fixture.setQueues( queueList ); fixture.init(); // 3. Set to capture the message argument passed to Messenger.send() ArgumentCaptor< Message > argument = ArgumentCaptor.forClass( Message.class ); // 4. Call the fixture fixture.markInProgress( osId, ACME_QUEUE ); // 5. Verify that send() was called (twice, right?) and gather second argument verify( messenger, times( 2 ) ).send( any( QueueId.class ), argument.capture() ); // 6. Assert that the fhId was in the message, which we have because it was captured // 6bis. Assert other stuff about the message generally Message result = argument.getValue(); assertNotNull( result.getProperty( FHID_PROPERTY ) ); assertTrue( result.getProperty( FHID_PROPERTY ).equals( DEFAULT_FHID ) ); assertNotNull( result.getProperty( ACME_TYPE_PROPERTY ) ); assertTrue( result.getProperty( ACME_TYPE_PROPERTY ).equals( ACME_QUEUE.getValue() ) ); assertTrue( result.getPriority() == Message.Q_PRIORITY_MEDIUM ); assertTrue( result.getMessageType().equals( MSG_TYPE ) ); }
Use of annotation @Mock and MockitoAnnotations.initMocks(this) to create a mock. Use of BDD given and returnsFirstArg().
public class TestMarkInProgressMsgImpl { ... private Message message = setupMessage(); private MarkInProgressMsgImpl fixture; @Mock private TransactionTypeRecorder transactionTypeRecorder; @Mock private ReservationMessageFactory reservationMessageFactory; @Mock private PrintingEventResponder printingEventResponder; @Mock private SensitiveDataMessageHelper sensitiveDataMessageHelper; @Mock private HeartBeatMonitor heartBeatMonitor; @BeforeMethod public void setUp() throws Exception { MockitoAnnotations.initMocks( this ); fixture = new MarkInProgressMsgImpl(); transactionTypeRecorder.setTransactionType( TransactionType.RESERVATION ); fixture.setTransactionTypeRecorder( transactionTypeRecorder ); fixture.setPrintingEventResponder( printingEventResponder ); fixture.setMessageFactory( reservationMessageFactory ); when( reservationMessageFactory.getInProgressPrimaryPrincipal( any( Message.class ) ) ).thenReturn( primaryPrincipalFtId.getIdAsServiceApiString() ); when( reservationMessageFactory.getInProgressType( any( Message.class ) ) ).thenReturn(Type.CEILING ); when( reservationMessageFactory.getInProgressChief( any( Message.class ) ) ).thenReturn( CHIEF_FTID ); when( reservationMessageFactory.getInProgressAssistant( any( Message.class ) ) ).thenReturn( ASSISTANT_FTID ); when( reservationMessageFactory.getInProgressCoworker( any( Message.class ) ) ).thenReturn( COWORKER_FTID ); when( reservationMessageFactory.getInProgressFhid( any( Message.class ) ) ).thenReturn( FHID ); given( sensitiveDataMessageHelper.embedPersonInformationInMessage( any( Message.class ) ) ).will( returnsFirstArg() ); }
And now, the "void" stub/mock: the doAnswer() wiggle above is only necessary if I want to extract a value from the mess down inside, which isn't always the case. If you just want to set up a void method in a mocked class, and want it to do nothing when called (that's pretty much what it will do anyway, but here we'll be explicit about it), then use doNothing():
doNothing().when(messenger).acknowledgeMessage(queueId, MESSAGE_ID);
When you're calling the same method with an indistinguishable argument passed to it over and over, yet want different answers (this is very pseudoish code...
when( dbc.callRestApi( "GET" ).thenReturn( new Response( "1" ), new Response( "2" ), new Response( "3" ) );
This is the old way to squirrel-cage create() in Mockito, pre 1.9.5.rc1.
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.AdditionalAnswers.returnsFirstArg; import static org.mockito.BDDMockito.given; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.bson.types.ObjectId; ... @Test public void testCreate_oldway() { Answer< Account > answer = new Answer< Account >() { public Account answer( InvocationOnMock invocation ) throws Throwable { Object[] args = invocation.getArguments(); Account account = ( Account ) args[ 0 ]; account.setOid( JACK_OID ); account.setIdentityoid( JACK_ID_OID ); account.setPassword( JACK_PASS ); account.setPartneroid( ACME_OID ); return account; } }; when( dao.create( any( Account.class ) ) ).thenAnswer( answer ); when( partnerDao.readByOid( ACME_OID ) ).thenReturn( ACME ); when( identityDao.readByOid( JACK_ID_OID ) ).thenReturn( JACK_ID ); when( dao.readByIdentityAndPartneroids( any( ObjectId.class ), any( ObjectId.class ) ) ).thenReturn( JACK ); AccountDto JACK_DTO = JACK.dto(); JACK_DTO.setOid( JACK_OID ); JACK_DTO.setPassword( JACK_PASS ); // (have to inject this artificially) try { manager.create( null, JACK_ID_OID, JACK_DTO ); fail( "Shouldn't get here because account already exists!" ); } catch( AppException e ) { log.info( "Test is successful if you get here." ); assertTrue( e.getHttpStatus() == Status.CONFLICT ); } }
The new way began in Mockito, 1.9.5.rc1.
@Test public void testCreate_newway() throws AppException { given( dao.create( ( Account ) anyObject() ) ).will( returnsFirstArg() ); when( partnerDao.readByOid( ACME_OID ) ).thenReturn( ACME ); when( identityDao.readByOid( JACK_ID_OID ) ).thenReturn( JACK_ID ); when( dao.readByIdentityAndPartneroids( any( ObjectId.class ), any( ObjectId.class ) ) ).thenReturn( null ); AccountDto JACK_DTO = JACK.dto(); JACK_DTO.setPartneroid( ACME_OID ); JACK_DTO.setPassword( JACK_PASS ); // (have to inject this artificially) Account result = manager.create( null, JACK_ID_OID, JACK_DTO ); verify( dao ).create( result ); assertNotNull( result ); assertTrue( EntityTestSupport.verifyPasswordHandled( result, JACK_PASS ) ); assertTrue( EntityTestSupport.verifyAccountResult( JACK, result ) ); }
Sometimes Mockito is grumpy when you use anyObject() in an argument list with raw types (string literals and the like—see "eat this" below). The error displayed will tell you, but you need to bracket those with eq():
import static org.mockito.Matchers.anyObject; ... import static org.mockito.Matchers.eq; @Test public void testCreate_newway() throws AppException { ... when( mocked.method( eq( "eat this" ), ( SomeClass ) anyObject() ) ).thenReturn( something ); ... }
This is a way to instantiate an abstract class that you want to test. After doing this, it's as if SomeClass were not abstract.
public class SomeClassTest { private SomeClass real; @Before public void setUp() { Mockito.mock( SomeClass.class, Mockito.CALLS_REAL_METHODS ); real.setX( 9 ); ... } @Test public void testSetX() { real.setX( 9 ); assertEquals( 9, read.getX() ); } } public abstract class SomeClass { private int x; ... public void setX( int x ) { this.x = x; } public int getX() { return this.x; } ... }
This still picks on me from time to time. I'm debugging through some code expecting not to execute a method call because it's mocked, but it crashes down inside (or does the wrong thing down inside) and I ask myself why Mockito didn't mock the method.
The answer is that Mockito will not mock methods that are static or final. In order to do that, remove final, re-interface above the class or visit PowerMock's functionality.
Here is some code that demonstrates a more elegant way of catching and verifying exceptions (predicted and on-purpose) in test code. Here we're testing the address manager of some web application. It's thin, it's simple, but we're doing it anyway to show this example. Code that implements validation of the address, complex, going over the wire to a third-party service, is what we're mocking. The AddressValidator chooses which of several possible validations to have the underlying Validator perform.
Spanning so much depth might not be the right way to do this, but I'm exploring it here also to hint at an underlying BaseValidator handling some dependency injection to prime the mocking pump. (Yes, this is essentially a note to myself and not a point I'm trying to make to anyone else.)
To accomplish this, we're mixing some Mockito and catch-exception, a library (free) from Google code.
The first, principal method, the one illustrating success, is pure Mockito. It's the second one, a mixture, that illustrates catch-exception since failure throws an AppException.
package com.acme; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.mockito.BDDMockito.when; import static org.mockito.Matchers.anyObject; import static com.googlecode.catchexception.CatchException.caughtException; import static com.googlecode.catchexception.CatchException.verifyException; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import com.acme.pojo.Address import com.acme.exception.AppException; import com.acme.validator.Validator; import com.acme.validator.AddressValidator; public class AddressManagerTest { private final static String STREET = "21 Jump Street"; private final static String CITY = "Beverley Hills"; private final static String STATE = "CA"; private final static String COUNTRY = "US"; private final static String ZIP = "12345"; private AddressManager manager; // class under test private Address proposed; // address POJO, as if from service layer... @Mock private Validator validator; // mocked; what the address validator calls @Before public void setup() { MockitoAnnotations.initMocks( this ); // make sure the mocked object gets injected into the object under test... manager = new AddressManager( validator ); proposed = new Address(); proposed.setStreet1( STREET ); proposed.setCity( CITY ); proposed.setState( STATE ); proposed.setCountry( COUNTRY ); proposed.setPostalcode( ZIP ); } @Test public void testVerifyAddress_success() throws AppException { SetupThreadContext.erectCaller(); when( validator.validateAddress( ( Address ) anyObject() ) ).thenReturn( true ); // if successful, this just returns proposed... Address result = manager.verifyAddress( proposed ); assertTrue( result == proposed ); } @Test public void testVerifyAddress_failure() throws AppException { SetupThreadContext.erectCaller(); // failing case throws an AppException with a specific message we can test for when( validator.validateAddress( ( Address ) anyObject() ) ).thenReturn( false ); verifyException( manager, AppException.class ).verifyAddress( proposed ); assertEquals( caughtException().getMessage(), AddressValidator.ADDRESS_FAILURE ); } }
Here's some background illustration (again, for me, not really for anyone else).
public class AddressValidator extends BaseValidator { public static final String ADDRESS_FAILURE = "service disapproves address"; public AddressValidator( Validator validator ) { super( validator ); } public AppException validate( Address address, Logger log ) throws AppException { boolean okay; try { okay = getValidator().validateAddress( address ); if( !okay ) return new AppException( ADDRESS_FAILURE ); } . . .
package com.hp.web.validator; public abstract class BaseValidator { private Validator validator; public BaseValidator( Validator validator ) { this.validator = validator; } public Validator getValidator() { return validator; } }
For this code, ...
when( mockedObject.stubbedMethod() ).thenReturn( X );
...the compiler give you this error:
Cannot resolve method 'thenReturn( X )'
This only means that X doesn't match what stubbedMethod() should return.
Concrete example: I have mocked AmazonSqsClient and want to specify how method GetQueueAttributes() should pretend to behave. I get:
Cannot resolve method 'thenReturn(resultMap)'
...in this code:
public class HaveFunWithSqs { private SqsOperations sqsOperations; @Mock private AmazonSqsClient awsClient; @BeforeMethod public void setup() { MockitoAnnotations.initMocks( this ); sqsOperations = new SqsOperations( /* stuff about queue */ ); } @Test public void test() { List< String > attributeNames = new ArrayList<>( 1 ); attributeNames.add( "ApproximateNumberOfMessages" ); Map< String, String > resultMap = new HashMap<>( 1 ); resultMap.put( "ApproximateNumberOfMessages", "27" ); when( awsClient.getQueueAttributes( attributeNames ) ).thenReturn( resultMap ); int result = sqsOperations.getMessageCount(); assertEqual( result, 27 ); } }
What I forgot was that AmazonSqsClient.getQueueAttribtes() returns the intermediate object, GetQueueAttributesResult; the resulting map I'm after is inside that:
@Test public void test() { List< String > attributeNames = new ArrayList<>( 1 ); attributeNames.add( "ApproximateNumberOfMessages" ); Map< String, String > resultMap = new HashMap<>( 1 ); resultMap.put( "ApproximateNumberOfMessages", "27" ); GetQueueAttributesResult attributesResult = new GetQueueAttributesResult(); attibutesResult.setAttributes( resultMap ); when( awsClient.getQueueAttributes( attributeNames ) ).thenReturn( attributesResult ); int result = sqsOperations.getMessageCount(); assertEqual( result, 27 ); }
Martin Fowler:
Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production.
Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.
Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.
From xunitpattern:
Mock Object: that implements the same interface as an object on which the SUT depends. We can use a Mock Object as an observation point when we need to do Behavior Verification to avoid having an Untested Requirement (see Production Bugs on page X) caused by an inability to observe side-effects of invoking methods on the SUT.
Stub: This implementation is configured to respond to calls from the SUT with the values (or exceptions) that will exercise the Untested Code (see Production Bugs on page X) within the SUT. A key indication for using a Test Stub is having Untested Code caused by the inability to control the indirect inputs of the SUT
Fake: We acquire or build a very lightweight implementation of the same functionality as provided by a component that the SUT depends on and instruct the SUT to use it instead of the real.
Another look...
Fake: a class that implements an interface but contains fixed data and no logic. Simply returns "good" or "bad" data depending on the implementation.
Mock: a class that implements an interface and allows the ability to dynamically set the values to return/exceptions to throw from particular methods and provides the ability to check if particular methods have been called/not called.
Stub: Like a mock class, except that it doesn't provide the ability to verify that methods have been called/not called.
And...
Stub: an object that provides predefined answers to method calls.
Mock: an object on which you set expectations.
Fake: an object with limited capabilities (for the purposes of testing), e.g. a fake web service.
Mocking everything in a test diminishes (radically) the good returns of unit tests. This decreases confidence because mocks are not real. It's crucial that unit tests test something, and that something should be logic—business rules, the outcome of sorting or parsing, etc. If the code, mocked up, is only contributing coordinating logic, that's not adding a log of value. Low-value unit tests are nevertheless code that must be carried around and maintained—at some expense.