$30 off During Our Annual Pro Sale. View Details »

Testing made sweet with a Mockito

Jeroen Mols
November 11, 2016

Testing made sweet with a Mockito

Slides from my talk at Devoxx Belgium 2016
video: https://www.youtube.com/shared?ci=gkLiuk-z61A

Thanks to many tools and libraries, writing unit tests is a breeze! So all your apps currently have >80% code coverage, right? Yay! Or wait... is it really? Is all your common logic (networking, databases,...) tested? Do you isolate parts of your code base to keep your tests small? And what about providing relevant testing data?

In order to achieve this, you need to make use of mocks and stubs. And that's exactly what this talk will be about: What is a mock? What's the difference between a mock and a stub? Are mocks the only way to provide relevant data for your unit tests? What do I do with final classes/methods in the SDKs I use? How do I architect my app to make it easier to test? ...

After having adopted TDD as my main development workflow for almost a year now, I feel comfortable saying everything can be tested. Its just a matter of having someone experience show you how.

Jeroen Mols

November 11, 2016
Tweet

More Decks by Jeroen Mols

Other Decks in Technology

Transcript

  1. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING MADE SWEET
    WITH A MOCKITO
    #DEVOXX #MOCKITO

    View Slide

  2. @MOLSJEROEN
    #DEVOXX #MOCKITO

    View Slide

  3. @MOLSJEROEN
    #DEVOXX #MOCKITO
    IF YOU DON’T LIKE UNIT TESTING YOUR
    PRODUCT, MOST LIKELY YOUR CUSTOMERS
    WON’T LIKE TO TEST IT EITHER.
    Unknown

    View Slide

  4. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ALWAYS WRITE A TEST TO REPRODUCE A
    BUG BEFORE YOU FIX IT
    Robert C. Martin*

    View Slide

  5. @MOLSJEROEN
    #DEVOXX #MOCKITO
    GOAL
    UI
    USER
    WEBSERVICE
    Button press
    Success/failure
    Update UI LOGININTERFACE
    RESPONSE
    Login/logout command

    View Slide

  6. @MOLSJEROEN
    #DEVOXX #MOCKITO
    GOAL
    UI
    USER
    WEBSERVICE
    Button press
    Login/logout command Success/failure
    Update UI LOGININTERFACE
    RESPONSE

    View Slide

  7. @MOLSJEROEN
    #DEVOXX #MOCKITO
    WAY OF WORKING
    #DEVOXX #MOCKITO

    View Slide

  8. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TEST REQUIREMENTS
    ▸ All tests must
    1. Run really fast
    2. Be small and focussed
    3. Reliable, not “flaky”
    ▸ Challenges: UI & WebService
    UI
    USER
    WEBSERVICE

    View Slide

  9. @MOLSJEROEN
    #DEVOXX #MOCKITO
    SOLUTION
    ▸ Isolate User
    ▸ Don’t include UI
    ▸ Replace WebService with dummy
    ▸ Mimic WebService behaviour
    ▸ => Verify interactions
    UI
    USER
    WEBSERVICE*

    View Slide

  10. @MOLSJEROEN
    #DEVOXX #MOCKITO
    DEFINITION: TEST DOUBLES
    ▸ Replace real class
    ▸ Same interface
    ▸ Different behaviour
    WEBSERVICE*
    WEBSERVICE
    public void login() {

    // NORMAL IMPL.

    }
    public void login() {

    // DO NOTHING

    }

    View Slide

  11. @MOLSJEROEN
    #DEVOXX #MOCKITO
    DEFINITION: TEST DOUBLES
    ▸ Replace real class
    ▸ Same interface
    ▸ Different behaviour
    WEBSERVICE
    public void login() {

    // NORMAL IMPL.

    }
    public void login() {

    // DO NOTHING

    }
    WEBSERVICE*

    View Slide

  12. @MOLSJEROEN
    #DEVOXX #MOCKITO
    DEFINITION: TEST DOUBLES
    ▸ Replace real class
    ▸ Same interface
    ▸ Different behaviour
    WEBSERVICE
    public void login() {

    // NORMAL IMPL.

    }
    public void login() {

    loginInterface.success();

    }
    WEBSERVICE*

    View Slide

  13. @MOLSJEROEN
    #DEVOXX #MOCKITO
    DEFINITION: TEST DOUBLES
    ▸ Replace real class
    ▸ Same interface
    ▸ Different behaviour
    WEBSERVICE
    public void login() {

    // NORMAL IMPL.

    }
    public void login() {

    throw new Exception();

    }
    WEBSERVICE*

    View Slide

  14. @MOLSJEROEN
    #DEVOXX #MOCKITO
    DEFINITION: MOCKS AND STUBS
    ▸ What is a mock?
    ▸ Generated class
    ▸ Doesn’t do anything
    ▸ Behaviour verification
    ▸ What is a stub?
    ▸ Handwritten class
    ▸ Returns predefined responses
    ▸ State verification

    View Slide

  15. @MOLSJEROEN
    #DEVOXX #MOCKITO
    MOCKITO
    #DEVOXX #MOCKITO

    View Slide

  16. @MOLSJEROEN
    #DEVOXX #MOCKITO
    Open source mocking framework that lets you write
    beautiful tests with a clean & simple API
    ▸ Documentation on mockito.org
    ▸ Source code on Github
    ▸ MIT license
    WHAT IS IT?

    View Slide

  17. @MOLSJEROEN
    #DEVOXX #MOCKITO
    WHY DRINK IT?
    ▸ Easy to use
    ▸ Very readable syntax
    ▸ No learning curve
    ▸ Annotation support
    ▸ Mature
    ▸ Large stackoverflow community
    ▸ Most popular Java / Android mocking framework

    View Slide

  18. @MOLSJEROEN
    #DEVOXX #MOCKITO
    HOW TO DRINK IT?
    ▸ PROJECT_HOME/build.gradle
    buildscript {

    repositories {

    jcenter()

    }

    }


    ▸ MODULE_HOME/build.gradle
    dependencies {

    ...

    testCompile “org.mockito:mockito-core:2.2.11"

    }

    View Slide

  19. @MOLSJEROEN
    #DEVOXX #MOCKITO
    HOW TO DRINK IT?
    ▸ PROJECT_HOME/build.gradle
    buildscript {

    repositories {

    jcenter()

    }

    }


    ▸ MODULE_HOME/build.gradle
    dependencies {

    ...

    testCompile “org.mockito:mockito-core:2.2.11"

    }

    View Slide

  20. @MOLSJEROEN
    #DEVOXX #MOCKITO
    INGREDIENTS
    #DEVOXX #MOCKITO

    View Slide

  21. @MOLSJEROEN
    #DEVOXX #MOCKITO
    INGREDIENTS
    ▸ Creating a mock
    ▸ Verifying interactions
    ▸ Stubbing methods
    ▸ Capturing arguments
    ▸ Mockito limitations

    View Slide

  22. @MOLSJEROEN
    #DEVOXX #MOCKITO
    INGREDIENTS
    ▸ Creating a mock
    ▸ Verifying interactions
    ▸ Stubbing methods
    ▸ Capturing arguments
    ▸ Mockito limitations

    View Slide

  23. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CREATING A MOCK
    import static org.mockito.Mockito.mock;
    @Test

    public void createMock() throws Exception {

    WebService mockWebService = mock(WebService.class);


    new User(mockWebService, 0, null);

    }

    View Slide

  24. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CREATING A MOCK
    import static org.mockito.Mockito.mock;
    @Test

    public void createMock() throws Exception {

    WebService mockWebService = mock(WebService.class);


    new User(mockWebService, 0, null);

    }

    View Slide

  25. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CREATING A MOCK
    import static org.mockito.Mockito.mock;
    @Test

    public void createMock() throws Exception {

    WebService mockWebService = mock(WebService.class);


    new User(mockWebService, 0, null);

    }

    View Slide

  26. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CREATING A MOCK - ANNOTATION
    @Rule

    public MockitoRule mockitoRule = MockitoJUnit.rule();


    @Mock

    private WebService mockWebService;
    @Test

    public void createMockUsingAnnotation() throws Exception {

    new User(mockWebService, 0, null);

    }

    View Slide

  27. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CREATING A MOCK - ANNOTATION
    @Rule

    public MockitoRule mockitoRule = MockitoJUnit.rule();


    @Mock

    private WebService mockWebService;
    @Test

    public void createMockUsingAnnotation() throws Exception {

    new User(mockWebService, 0, null);

    }

    View Slide

  28. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CREATING A MOCK - ANNOTATION
    @Rule

    public MockitoRule mockitoRule = MockitoJUnit.rule();


    @Mock

    private WebService mockWebService;
    @Test

    public void createMockUsingAnnotation() throws Exception {

    new User(mockWebService, 0, null);

    }

    View Slide

  29. @MOLSJEROEN
    #DEVOXX #MOCKITO
    INGREDIENTS
    ▸ Creating a mock
    ▸ Verifying interactions
    ▸ Stubbing methods
    ▸ Capturing arguments
    ▸ Mockito limitations

    View Slide

  30. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS
    @Test

    public void verifyInteractionTimes() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.logout();


    verify(mockWebService).logout();

    }

    View Slide

  31. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS
    @Test

    public void verifyInteractionTimes() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.logout();


    verify(mockWebService).logout();

    }

    View Slide

  32. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - TIMES
    @Test

    public void verifyInteractionTimes() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.logout();


    verify(mockWebService, times(1) ).logout();

    atLeast(1)

    atLeastOnce()

    atMost(1)

    only()

    never()

    }

    View Slide

  33. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - TIMES
    @Test

    public void verifyInteractionTimes() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.logout();


    verify(mockWebService, times(1) ).logout();

    atLeast(1)

    atLeastOnce()

    atMost(1)

    only()

    never()

    }
    ▸ Being overly restrictive makes tests brittle!

    View Slide

  34. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - PARAMETERS
    @Test

    public void verifyInteractionParameters() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.login(null);


    verify(mockWebService).login(USER_ID);

    }

    View Slide

  35. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - PARAMETERS
    @Test

    public void verifyInteractionParameters() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.login(null);


    verify(mockWebService).login(anyInt() );
    anyString()
    any(Response.class)

    }

    View Slide

  36. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - PARAMETERS
    @Test

    public void verifyInteractionParameters() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.login(null);


    verify(mockWebService).login(anyInt(), eq(PASSWORD));

    }
    ▸ One matcher -> all arguments need to be matchers

    View Slide

  37. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - PARAMETERS
    @Test

    public void verifyInteractionParameters() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.login(null);


    verify(mockWebService).login(gt(0) );

    lt(10000)
    leq(10000)

    }

    View Slide

  38. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - PARAMETERS
    @Test

    public void verifyInteractionParameters() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.login(null);


    verify(mockWebService).login(startsWith(“n1") );

    contains(“c3")
    matches("n[1-9]{1}c[1-9]{1}try")
    }

    View Slide

  39. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - PARAMETERS
    @Test

    public void verifyInteractionParameters() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.login(null);


    verify(mockWebService).login(isNotNull(Response.class)) );
    not(eq(0))
    not(eq(“12345678"))
    and(gt(0), lt(1000000000))

    }
    ▸ Mockito.Matchers
    ▸ Mockito.AdditionalMatchers

    View Slide

  40. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - ORDER
    @Test

    public void verifyInteractionOrder() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.login(null);

    user.logout();


    InOrder inOrder = inOrder(mockWebService);

    inOrder.verify(mockWebService).login();

    inOrder.verify(mockWebService).logout();

    }

    View Slide

  41. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - ORDER
    @Test

    public void verifyInteractionOrder() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.login(null);

    user.logout();


    InOrder inOrder = inOrder(mockWebService);

    inOrder.verify(mockWebService).login();

    inOrder.verify(mockWebService).logout();

    }

    View Slide

  42. @MOLSJEROEN
    #DEVOXX #MOCKITO
    VERIFYING INTERACTIONS - ORDER
    @Test

    public void verifyInteractionOrder() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);


    user.login(null);

    user.logout();


    InOrder inOrder = inOrder(mockWebService);

    inOrder.verify(mockWebService).login();

    inOrder.verify(mockWebService).logout();

    }

    View Slide

  43. @MOLSJEROEN
    #DEVOXX #MOCKITO
    INGREDIENTS
    ▸ Creating a mock
    ▸ Verifying interactions
    ▸ Stubbing methods
    ▸ Capturing arguments
    ▸ Mockito limitations

    View Slide

  44. @MOLSJEROEN
    #DEVOXX #MOCKITO
    STUBBING METHODS
    @Test

    public void stubMethod() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    when(mockWebService.isOffline()).thenReturn(true);


    user.login(mockLoginInterface);


    verify(mockWebService, never()).login();

    }

    View Slide

  45. @MOLSJEROEN
    #DEVOXX #MOCKITO
    STUBBING METHODS
    @Test

    public void stubMethod() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    when(mockWebService.isOffline()).thenReturn(true);


    user.login(mockLoginInterface);


    verify(mockWebService, never()).login();

    }

    View Slide

  46. @MOLSJEROEN
    #DEVOXX #MOCKITO
    STUBBING METHODS
    @Test

    public void stubMethod() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    when(mockWebService.isOffline()).thenReturn(true);


    user.login(mockLoginInterface);


    verify(mockWebService, never()).login();

    }

    View Slide

  47. @MOLSJEROEN
    #DEVOXX #MOCKITO
    STUBBING METHODS
    @Test

    public void stubMethod() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    when(mockWebService.isOffline()).thenReturn(true, false, true);


    user.login(mockLoginInterface);


    verify(mockWebService, never()).login();

    }

    View Slide

  48. @MOLSJEROEN
    #DEVOXX #MOCKITO
    STUBBING METHODS
    @Test

    public void stubMethod() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    when(mockWebService.isOffline()).thenThrow(MyException.class);


    user.login(mockLoginInterface);


    verify(mockWebService, never()).login();

    }

    View Slide

  49. @MOLSJEROEN
    #DEVOXX #MOCKITO
    STUBBING METHODS
    @Test

    public void stubMethod() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    when(mockWebService.isOffline()).then(new Answer() {

    int index = 0;


    @Override

    public Boolean answer(InvocationOnMock in) throws … {

    return index++ % 2 > 0;

    }

    });

    user.login(mockLoginInterface);


    verify(mockWebService, never()).login();

    }

    View Slide

  50. @MOLSJEROEN
    #DEVOXX #MOCKITO
    STUBBING METHODS
    ▸ Normal syntax
    when(mockWebService.isOffline()).thenReturn(true);

    ▸ Alternative syntax
    doReturn(true).when(mockWebService).isOffline();

    ▸ BDD syntax
    given(mockWebService.isOffline()).willReturn(true);

    View Slide

  51. @MOLSJEROEN
    #DEVOXX #MOCKITO
    STUBBING METHODS
    ▸ Normal syntax
    when(mockWebService.isOffline()).thenReturn(true);

    ▸ Alternative syntax
    doReturn(true).when(mockWebService).isOffline();

    ▸ BDD syntax
    given(mockWebService.isOffline()).willReturn(true);

    View Slide

  52. @MOLSJEROEN
    #DEVOXX #MOCKITO
    STUBBING METHODS
    ▸ Normal syntax
    when(mockWebService.isOffline()).thenReturn(true);

    ▸ Alternative syntax
    doReturn(true).when(mockWebService).isOffline();

    ▸ BDD syntax
    given(mockWebService.isOffline()).willReturn(true);

    View Slide

  53. @MOLSJEROEN
    #DEVOXX #MOCKITO
    INGREDIENTS
    ▸ Creating a mock
    ▸ Verifying interactions
    ▸ Stubbing methods
    ▸ Capturing arguments
    ▸ Mockito limitations

    View Slide

  54. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS - PROBLEM STATEMENT
    UI
    USER
    WEBSERVICE*
    Button press
    Success/failure
    Update UI LOGININTERFACE*
    RESPONSE
    Login command

    View Slide

  55. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS - PROBLEM STATEMENT
    UI
    USER
    WEBSERVICE*
    Button press
    Success/failure
    Update UI LOGININTERFACE*
    RESPONSE
    Login command

    View Slide

  56. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS - CHALLENGE
    public void login(final LoginInterface loginInterface) {
    Response response = new Response() {

    @Override

    public void onRequestCompleted(…) {

    ...
    }
    }

    webService.login(userId, password, response);

    }
    UI USER WEBSERVICE*
    LOGININTERFACE* RESPONSE

    View Slide

  57. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS - CHALLENGE
    public void login(final LoginInterface loginInterface) {
    Response response = new Response() {

    @Override

    public void onRequestCompleted(…) {

    ...
    }
    }

    webService.login(userId, password, response);

    }
    UI USER WEBSERVICE*
    LOGININTERFACE* RESPONSE

    View Slide

  58. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS - PROBLEM STATEMENT
    public class Response {

    public void onRequestCompleted(boolean success, String data){

    if (success) {

    loginInterface.onLoginSuccess();

    } else {

    loginInterface.onLoginFailed();

    }

    }
    }
    UI USER WEBSERVICE*
    LOGININTERFACE* RESPONSE

    View Slide

  59. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS - PROBLEM STATEMENT
    public class Response {

    public void onRequestCompleted(boolean success, String data){

    if (success) {

    loginInterface.onLoginSuccess();

    } else {

    loginInterface.onLoginFailed();

    }

    }
    }
    UI USER WEBSERVICE*
    LOGININTERFACE* RESPONSE

    View Slide

  60. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS - SOLUTION
    UI
    USER
    WEBSERVICE*
    Button press
    Success/failure
    Update UI LOGININTERFACE*
    RESPONSE
    1 Login command

    View Slide

  61. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS - SOLUTION
    UI
    USER
    WEBSERVICE*
    Button press
    Success/failure
    Update UI LOGININTERFACE*
    2
    Login command
    Capture
    response
    RESPONSE

    View Slide

  62. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS - SOLUTION
    UI
    USER
    Button press
    Success/failure
    Update UI
    3
    WEBSERVICE*
    LOGININTERFACE*
    RESPONSE
    Login command

    View Slide

  63. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS - SOLUTION
    UI
    USER
    WEBSERVICE*
    Button press
    Success/failure
    Update UI LOGININTERFACE*
    RESPONSE
    4
    Login command

    View Slide

  64. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS
    @Test

    public void captureArguments() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    user.login(mockLoginInterface);

    verify(mockWebService).login(responseCaptor.capture());

    Response response = responseCaptor.getValue();


    response.onRequestCompleted(true);


    verify(mockLoginInterface).onLoginSuccess();

    }
    UI USER WEBSERVICE*
    LOGININTERFACE* RESPONSE

    View Slide

  65. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS
    @Captor

    private ArgumentCaptor responseCaptor;
    UI USER WEBSERVICE*
    LOGININTERFACE* RESPONSE
    0

    View Slide

  66. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS
    @Test

    public void captureArguments() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    user.login(mockLoginInterface);

    verify(mockWebService).login(responseCaptor.capture());

    Response response = responseCaptor.getValue();


    response.onRequestCompleted(true);


    verify(mockLoginInterface).onLoginSuccess();

    }
    UI USER WEBSERVICE*
    LOGININTERFACE* RESPONSE
    1

    View Slide

  67. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS
    @Test

    public void captureArguments() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    user.login(mockLoginInterface);

    verify(mockWebService).login(responseCaptor.capture());

    Response response = responseCaptor.getValue();


    response.onRequestCompleted(true);


    verify(mockLoginInterface).onLoginSuccess();

    }
    UI USER WEBSERVICE*
    LOGININTERFACE* RESPONSE
    2

    View Slide

  68. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS
    @Test

    public void captureArguments() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    user.login(mockLoginInterface);

    verify(mockWebService).login(responseCaptor.capture());

    Response response = responseCaptor.getValue();


    response.onRequestCompleted(true);


    verify(mockLoginInterface).onLoginSuccess();

    }
    UI USER WEBSERVICE*
    LOGININTERFACE* RESPONSE
    3

    View Slide

  69. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CAPTURING ARGUMENTS
    @Test

    public void captureArguments() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    user.login(mockLoginInterface);

    verify(mockWebService).login(responseCaptor.capture());

    Response response = responseCaptor.getValue();


    response.onRequestCompleted(true);


    verify(mockLoginInterface).onLoginSuccess();

    }
    UI USER WEBSERVICE*
    LOGININTERFACE* RESPONSE
    4

    View Slide

  70. @MOLSJEROEN
    #DEVOXX #MOCKITO
    INGREDIENTS
    ▸ Creating a mock
    ▸ Verifying interactions
    ▸ Stubbing methods
    ▸ Capturing arguments
    ▸ Mockito limitations

    View Slide

  71. @MOLSJEROEN
    #DEVOXX #MOCKITO
    MOCKITO LIMITATIONS
    ▸ Unable to mock
    ▸ final classes => opt-in with Mockito 2.x
    ▸ final methods => opt-in with Mockito 2.x
    ▸ static methods
    ▸ private methods
    ▸ hashCode() and equals()

    View Slide

  72. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ADVANCED MOCKITO
    #DEVOXX #MOCKITO

    View Slide

  73. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ADVANCED MOCKITO
    ▸ Testing UI
    ▸ Running Mockito on an Android device
    ▸ Custom Matchers
    ▸ Testing final and static
    ▸ Testing data
    ▸ New creation
    ▸ Power tips

    View Slide

  74. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ADVANCED MOCKITO
    ▸ Testing UI
    ▸ Running Mockito on an Android device
    ▸ Custom Matchers
    ▸ Testing final and static
    ▸ Testing data
    ▸ New creation
    ▸ Power tips

    View Slide

  75. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ▸ Model View Presenter
    ▸ Mock view & model
    ▸ Fully test presenter
    ▸ UI == “pass through”
    ▸ Dependency injection
    ▸ Only “inward pointing” dependencies
    TESTING UI
    MODEL
    VIEW
    PRESENTER
    VIEW
    IMPLEMENTATION

    View Slide

  76. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ADVANCED MOCKITO
    ▸ Testing UI
    ▸ Running Mockito on an Android device
    ▸ Custom Matchers
    ▸ Testing final and static
    ▸ Testing data
    ▸ New creation
    ▸ Power tips

    View Slide

  77. @MOLSJEROEN
    #DEVOXX #MOCKITO
    RUNNING MOCKITO ON AN ANDROID DEVICE
    ▸ MODULE_HOME/build.gradle
    defaultConfig {



    testInstrumentationRunner 

    "android.support.test.runner.AndroidJUnitRunner"

    }
    dependencies {



    androidTestCompile 'com.android.support.test:runner:0.5'

    androidTestCompile 'com.android.support.test:rules:0.5'

    androidTestCompile 'org.mockito:mockito-core:1.10.19'

    androidTestCompile 'com.crittercism.dexmaker:dexmaker:1.4'

    androidTestCompile 'com.crittercism.dexmaker:dexmaker-dx:1.4'
    androidTestCompile 'com.crittercism.dexmaker:dexmaker-mockito:1.4'

    }

    View Slide

  78. @MOLSJEROEN
    #DEVOXX #MOCKITO
    RUNNING MOCKITO ON AN ANDROID DEVICE
    ▸ MODULE_HOME/build.gradle
    defaultConfig {



    testInstrumentationRunner 

    "android.support.test.runner.AndroidJUnitRunner"

    }
    dependencies {



    androidTestCompile 'com.android.support.test:runner:0.5'

    androidTestCompile 'com.android.support.test:rules:0.5'

    androidTestCompile 'org.mockito:mockito-core:1.10.19'

    androidTestCompile 'com.crittercism.dexmaker:dexmaker:1.4'

    androidTestCompile 'com.crittercism.dexmaker:dexmaker-dx:1.4'
    androidTestCompile 'com.crittercism.dexmaker:dexmaker-mockito:1.4'

    }

    View Slide

  79. @MOLSJEROEN
    #DEVOXX #MOCKITO
    RUNNING MOCKITO ON AN ANDROID DEVICE
    ▸ MODULE_HOME/build.gradle
    defaultConfig {



    testInstrumentationRunner 

    "android.support.test.runner.AndroidJUnitRunner"

    }
    dependencies {



    androidTestCompile 'com.android.support.test:runner:0.5'

    androidTestCompile 'com.android.support.test:rules:0.5'

    androidTestCompile 'org.mockito:mockito-core:1.10.19'

    androidTestCompile 'com.crittercism.dexmaker:dexmaker:1.4'

    androidTestCompile 'com.crittercism.dexmaker:dexmaker-dx:1.4'
    androidTestCompile 'com.crittercism.dexmaker:dexmaker-mockito:1.4'

    }

    View Slide

  80. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ADVANCED MOCKITO
    ▸ Testing UI
    ▸ Running Mockito on an Android device
    ▸ Custom Matchers
    ▸ Testing final and static
    ▸ Testing data
    ▸ New creation
    ▸ Power tips

    View Slide

  81. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CUSTOM MATCHER - LIST CONTAINS
    public class ListContains implements ArgumentMatcher {


    private final T object;


    public ListContains(T object) {

    this.object = object;

    }


    public boolean matches(List list) {

    return list.contains(object);

    }


    public String toString() {

    //printed in verification errors

    return "[list doesn't contain object]";

    }

    }

    View Slide

  82. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CUSTOM MATCHER - LIST CONTAINS
    public class ListContains implements ArgumentMatcher {


    private final T object;


    public ListContains(T object) {

    this.object = object;

    }


    public boolean matches(List list) {

    return list.contains(object);

    }


    public String toString() {

    //printed in verification errors

    return "[list doesn't contain object]";

    }

    }

    View Slide

  83. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CUSTOM MATCHER - LIST CONTAINS
    public class ListContains implements ArgumentMatcher {


    private final T object;


    public ListContains(T object) {

    this.object = object;

    }


    public boolean matches(List list) {

    return list.contains(object);

    }


    public String toString() {

    //printed in verification errors

    return "[list doesn't contain object]";

    }

    }

    View Slide

  84. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CUSTOM MATCHER - LIST CONTAINS
    public class ListContains implements ArgumentMatcher {


    private final T object;


    public ListContains(T object) {

    this.object = object;

    }


    public boolean matches(List list) {

    return list.contains(object);

    }


    public String toString() {

    //printed in verification errors

    return "[list doesn't contain object]";

    }

    }

    View Slide

  85. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CUSTOM MATCHER - LIST CONTAINS
    public class ListContains implements ArgumentMatcher {


    private final T object;


    public ListContains(T object) {

    this.object = object;

    }


    public boolean matches(List list) {

    return list.contains(object);

    }


    public String toString() {

    //printed in verification errors

    return "[list doesn't contain object]";

    }

    }

    View Slide

  86. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CUSTOM MATCHER - STATIC METHOD
    public class ListMatchers {


    @Nullable

    public static List listContains(K object) {

    return argThat(new ListContains<>(object));

    }

    }

    View Slide

  87. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CUSTOM MATCHER - STATIC METHOD
    public class ListMatchers {


    @Nullable

    public static List listContains(K object) {

    return argThat(new ListContains<>(object));

    }

    }

    View Slide

  88. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CUSTOM MATCHER - STATIC METHOD
    public class ListMatchers {


    @Nullable

    public static List listContains(K object) {

    return argThat(new ListContains<>(object));

    }

    }

    View Slide

  89. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TRADITIONAL TEST - ARGUMENTCAPTOR
    @Test
    public void argumentCaptorTest() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    ArgumentCaptor> listCaptor = ...;

    String expectedMessage = "Test message";


    user.sendMessage(expectedMessage);


    verify(mockWebService).sendMessages(listCaptor.capture());

    List messages = listCaptor.getValue();

    String actualMessage = messages.get(0);


    assertEquals(expectedMessage, actualMessage);

    }

    View Slide

  90. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TRADITIONAL TEST - ARGUMENTCAPTOR
    @Test
    public void argumentCaptorTest() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    ArgumentCaptor> listCaptor = ...;

    String expectedMessage = "Test message";


    user.sendMessage(expectedMessage);


    verify(mockWebService).sendMessages(listCaptor.capture());

    List messages = listCaptor.getValue();

    String actualMessage = messages.get(0);


    assertEquals(expectedMessage, actualMessage);

    }

    View Slide

  91. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TRADITIONAL TEST - ARGUMENTCAPTOR
    @Test
    public void argumentCaptorTest() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    ArgumentCaptor> listCaptor = ...;

    String expectedMessage = "Test message";


    user.sendMessage(expectedMessage);


    verify(mockWebService).sendMessages(listCaptor.capture());

    List messages = listCaptor.getValue();

    String actualMessage = messages.get(0);


    assertEquals(expectedMessage, actualMessage);

    }

    View Slide

  92. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CUSTOM MATCHER TEST
    @TestTest

    public void customMatcherTest() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    String message = "Test message";

    user.sendMessage(message);


    verify(mockWebService).sendMessages(listContains(message));

    }

    View Slide

  93. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CUSTOM MATCHER TEST
    @TestTest

    public void customMatcherTest() throws Exception {

    User user = new User(mockWebService, USER_ID, PASSWORD);

    String message = "Test message";

    user.sendMessage(message);


    verify(mockWebService).sendMessages(listContains(message));

    }
    RELATED BLOGPOSTS

    View Slide

  94. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ADVANCED MOCKITO
    ▸ Testing UI
    ▸ Running Mockito on an Android device
    ▸ Custom Matchers
    ▸ Testing final and static
    ▸ Testing data
    ▸ New creation
    ▸ Power tips

    View Slide

  95. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING FINAL METHODS / CLASSES
    public class Handler {


    public Handler() {};


    public final boolean post(Runnable r) {

    // internal implementation

    }


    public final boolean sendMessage(Message msg) {

    // internal implementation

    }

    }

    View Slide

  96. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING FINAL METHODS / CLASSES
    public class Handler {


    public Handler() {};


    public final boolean post(Runnable r) {

    // internal implementation

    }


    public final boolean sendMessage(Message msg) {

    // internal implementation

    }

    }

    View Slide

  97. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING FINAL METHODS / CLASSES
    public class HandlerWrapper {


    private final Handler handler;


    public HandlerWrapper() {

    handler = new Handler();

    }


    public boolean post(Runnable r) {

    return handler.post(r);

    }


    public boolean sendMessage(Message msg) {

    return handler.sendMessage(msg);

    }

    }

    View Slide

  98. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING FINAL METHODS / CLASSES
    public class HandlerWrapper {


    private final Handler handler;


    public HandlerWrapper() {

    handler = new Handler();

    }


    public boolean post(Runnable r) {

    return handler.post(r);

    }


    public boolean sendMessage(Message msg) {

    return handler.sendMessage(msg);

    }

    }

    View Slide

  99. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING FINAL METHODS / CLASSES
    public class HandlerWrapper {


    private final Handler handler;


    public HandlerWrapper() {

    handler = new Handler();

    }


    public boolean post(Runnable r) {

    return handler.post(r);

    }


    public boolean sendMessage(Message msg) {

    return handler.sendMessage(msg);

    }

    }

    View Slide

  100. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING FINAL METHODS/CLASSES - MOCKITO 2.X
    ▸ Opt-in process
    ▸ Create new file
    ▸ name: org.mockito.plugins.MockMaker
    ▸ path: src/test/resources/mockito-extensions
    ▸ contents: mock-maker-inline

    View Slide

  101. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING STATIC METHODS
    public class NativeCamera {


    private Camera camera = null;


    public Camera getNativeCamera() {

    return camera;

    }


    public void openNativeCamera() throws RuntimeException {

    camera = Camera.open(CameraInfo.CAMERA_FACING_BACK);

    }


    public void releaseNativeCamera() {

    camera.release();

    }

    }

    View Slide

  102. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING STATIC METHODS
    public class NativeCamera {


    private Camera camera = null;


    public Camera getNativeCamera() {

    return camera;

    }


    public void openNativeCamera() throws RuntimeException {

    camera = Camera.open(CameraInfo.CAMERA_FACING_BACK);

    }


    public void releaseNativeCamera() {

    camera.release();

    }

    }

    View Slide

  103. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ADVANCED MOCKITO
    ▸ Testing UI
    ▸ Running Mockito on an Android device
    ▸ Custom Matchers
    ▸ Testing final and static
    ▸ Testing data
    ▸ New creation
    ▸ Power tips

    View Slide

  104. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING DATA
    @Test

    public void mockData() throws Exception {

    UserData mock = mock(UserData.class);

    when(mock.getFirstName()).thenReturn("FirstName");

    when(mock.getLastName()).thenReturn("LastName");

    when(mock.getUserId()).thenReturn(1111007);


    when(mock.getStreet()).thenReturn("StreetName");

    when(mock.getHouseNumber()).thenReturn(1);

    when(mock.getCity()).thenReturn("City");

    when(mock.getCountry()).thenReturn("Country");


    // Use mock in further test

    }

    View Slide

  105. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING DATA
    @Test

    public void testData() throws Exception {

    UserData userData = new TestUserData();


    // use mock in further test

    }
    public class TestUserData extends UserData {
    @Override

    public String getFirstName() {

    return "FirstName";

    }

    ...
    }

    View Slide

  106. @MOLSJEROEN
    #DEVOXX #MOCKITO
    TESTING DATA
    @Test

    public void testData() throws Exception {

    UserData userData = new TestUserData();


    // use mock in further test

    }
    public class TestUserData extends UserData {
    @Override

    public String getFirstName() {

    return "FirstName";

    }

    ...
    }

    View Slide

  107. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ADVANCED MOCKITO
    ▸ Testing UI
    ▸ Running Mockito on an Android device
    ▸ Custom Matchers
    ▸ Testing final and static
    ▸ Testing data
    ▸ New creation
    ▸ Power tips

    View Slide

  108. @MOLSJEROEN
    #DEVOXX #MOCKITO
    NEW CREATION
    public User(int userId, String password) {

    this.webService = new WebService();

    }
    ▸ Internal created objects
    ▸ almost impossible to test
    ▸ avoid for long lived objects

    View Slide

  109. @MOLSJEROEN
    #DEVOXX #MOCKITO
    NEW CREATION
    public User(int userId, String password) {

    this.webService = new WebService();

    }
    ▸ Internal created objects
    ▸ almost impossible to test
    ▸ avoid for long lived objects

    View Slide

  110. @MOLSJEROEN
    #DEVOXX #MOCKITO
    NEW CREATION
    public User(int userId, String password) {

    this.webService = new WebService();

    }
    ▸ Dependency injection
    public User(WebService webService, int user, String password) {

    if (webService == null) {

    throw new RuntimeException("Webservice required");

    }

    this.webService = webService;

    }

    View Slide

  111. @MOLSJEROEN
    #DEVOXX #MOCKITO
    NEW CREATION
    public User(int userId, String password) {

    this.webService = new WebService();

    }
    ▸ Factory pattern
    public User(WebServiceFactory factory, int user, String pw) {

    this.webService = factory.createWebService();

    }

    View Slide

  112. @MOLSJEROEN
    #DEVOXX #MOCKITO
    ADVANCED MOCKITO
    ▸ Testing UI
    ▸ Running Mockito on an Android device
    ▸ Custom Matchers
    ▸ Testing final and static
    ▸ Testing data
    ▸ New creation
    ▸ Power tips

    View Slide

  113. @MOLSJEROEN
    #DEVOXX #MOCKITO
    IF YOU’RE NOT WRITING TESTS, YOU’RE
    WRITING INSTANT LEGACY.
    Michael feathers*

    View Slide

  114. @MOLSJEROEN
    #DEVOXX #MOCKITO
    POWER TIPS
    ▸ Avoid singletons
    ▸ Avoid Android instrumentation tests
    ▸ Isolate non testable code
    ▸ Don’t use Spies
    ▸ Don’t nest mocks
    ▸ Avoid using “For testing methods”

    View Slide

  115. @MOLSJEROEN
    #DEVOXX #MOCKITO
    WRAP UP
    #DEVOXX #MOCKITO

    View Slide

  116. @MOLSJEROEN
    #DEVOXX #MOCKITO
    IT IS BETTER TO HAVE A SIMPLE TEST THAT
    WORKS THAN A COMPLICATED TEST THAT
    SEEMS TO WORK.
    Mockito documentation

    View Slide

  117. @MOLSJEROEN
    #DEVOXX #MOCKITO
    CONCLUSION
    ▸ Mockito makes mocking & stubbing easy
    ▸ Avoid creating internal objects
    ▸ Choose a good testing strategy
    ▸ Don’t overuse the power features
    ▸ Keep unit tests small and focussed
    ▸ Consider refactoring
    ▸ Prefer tests on the java VM

    View Slide

  118. @MOLSJEROEN
    #DEVOXX #MOCKITO
    REFERENCES
    ▸ Mockito homepage http://mockito.org/
    ▸ Mockito reference card https://dzone.com/refcardz/mockito
    ▸ Dexmaker https://github.com/crittercism/dexmaker
    ▸ Sample code
    ▸ MockitoExample https://github.com/JeroenMols/MockitoExample
    ▸ LandscapeVideoCamera https://github.com/JeroenMols/LandscapeVideoCamera
    ▸ MockitoColletionMatchers https://github.com/JeroenMols/MockitoCollectionMatchers

    View Slide

  119. @MOLSJEROEN
    #DEVOXX #MOCKITO
    IMAGE CREDITS
    ▸ Mojito

    https://indraneescookingcorner.blogspot.be/2014/08/virgin-mojito.html
    ▸ Philips Hue living room

    http://www.philips.de
    ▸ Bartender set

    http://www.vinspireuk.com/2014/12/cocktail-gifts-for-cocktail-lovers.html
    ▸ Mojito ingredients

    https://www.nelleulla.com/lv-en/products/truffles/4-mojito-truffle
    ▸ Mockito Mojito

    http://www.seedylawyer.com/history-of-hemingways-mojitos/
    ▸ Raspberry Mojito

    http://goodpixcool.com/raspberry+mojito+in+a+bottle?image=99002602
    ▸ Drinking Mojito

    https://www.lancerskincare.com/blog/10-ways-to-age-your-skin-prematurely/

    View Slide

  120. @MOLSJEROEN
    #DEVOXX #MOCKITO
    MANY THANKS
    ▸ Jeroen Mols (Belgium)
    ▸ @MolsJeroen
    ▸ http://jeroenmols.com/blog

    View Slide