Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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 IF YOU DON’T LIKE UNIT TESTING YOUR

    PRODUCT, MOST LIKELY YOUR CUSTOMERS WON’T LIKE TO TEST IT EITHER. Unknown
  2. @MOLSJEROEN #DEVOXX #MOCKITO ALWAYS WRITE A TEST TO REPRODUCE A

    BUG BEFORE YOU FIX IT Robert C. Martin*
  3. @MOLSJEROEN #DEVOXX #MOCKITO GOAL UI USER WEBSERVICE Button press Success/failure

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

    command Success/failure Update UI LOGININTERFACE RESPONSE
  5. @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
  6. @MOLSJEROEN #DEVOXX #MOCKITO SOLUTION ▸ Isolate User ▸ Don’t include

    UI ▸ Replace WebService with dummy ▸ Mimic WebService behaviour ▸ => Verify interactions UI USER WEBSERVICE*
  7. @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 
 }
  8. @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*
  9. @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*
  10. @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*
  11. @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
  12. @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?
  13. @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
  14. @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"
 }
  15. @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"
 }
  16. @MOLSJEROEN #DEVOXX #MOCKITO INGREDIENTS ▸ Creating a mock ▸ Verifying

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

    interactions ▸ Stubbing methods ▸ Capturing arguments ▸ Mockito limitations
  18. @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);
 }
  19. @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);
 }
  20. @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);
 }
  21. @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);
 }
  22. @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);
 }
  23. @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);
 }
  24. @MOLSJEROEN #DEVOXX #MOCKITO INGREDIENTS ▸ Creating a mock ▸ Verifying

    interactions ▸ Stubbing methods ▸ Capturing arguments ▸ Mockito limitations
  25. @MOLSJEROEN #DEVOXX #MOCKITO VERIFYING INTERACTIONS @Test
 public void verifyInteractionTimes() throws

    Exception {
 User user = new User(mockWebService, USER_ID, PASSWORD);
 
 user.logout();
 
 verify(mockWebService).logout();
 }
  26. @MOLSJEROEN #DEVOXX #MOCKITO VERIFYING INTERACTIONS @Test
 public void verifyInteractionTimes() throws

    Exception {
 User user = new User(mockWebService, USER_ID, PASSWORD);
 
 user.logout();
 
 verify(mockWebService).logout();
 }
  27. @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()
 }
  28. @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!
  29. @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);
 }
  30. @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)
 }
  31. @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
  32. @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)
 }
  33. @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") }
  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(isNotNull(Response.class)) ); not(eq(0)) not(eq(“12345678")) and(gt(0), lt(1000000000))
 } ▸ Mockito.Matchers ▸ Mockito.AdditionalMatchers
  35. @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();
 }
  36. @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();
 }
  37. @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();
 }
  38. @MOLSJEROEN #DEVOXX #MOCKITO INGREDIENTS ▸ Creating a mock ▸ Verifying

    interactions ▸ Stubbing methods ▸ Capturing arguments ▸ Mockito limitations
  39. @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();
 }
  40. @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();
 }
  41. @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();
 }
  42. @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();
 }
  43. @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();
 }
  44. @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<Boolean>() {
 int index = 0;
 
 @Override
 public Boolean answer(InvocationOnMock in) throws … {
 return index++ % 2 > 0;
 }
 }); 
 user.login(mockLoginInterface);
 
 verify(mockWebService, never()).login();
 }
  45. @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);
  46. @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);
  47. @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);
  48. @MOLSJEROEN #DEVOXX #MOCKITO INGREDIENTS ▸ Creating a mock ▸ Verifying

    interactions ▸ Stubbing methods ▸ Capturing arguments ▸ Mockito limitations
  49. @MOLSJEROEN #DEVOXX #MOCKITO CAPTURING ARGUMENTS - PROBLEM STATEMENT UI USER

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

    WEBSERVICE* Button press Success/failure Update UI LOGININTERFACE* RESPONSE Login command
  51. @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
  52. @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
  53. @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
  54. @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
  55. @MOLSJEROEN #DEVOXX #MOCKITO CAPTURING ARGUMENTS - SOLUTION UI USER WEBSERVICE*

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

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

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

    Button press Success/failure Update UI LOGININTERFACE* RESPONSE 4 Login command
  59. @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
  60. @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
  61. @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
  62. @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
  63. @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
  64. @MOLSJEROEN #DEVOXX #MOCKITO INGREDIENTS ▸ Creating a mock ▸ Verifying

    interactions ▸ Stubbing methods ▸ Capturing arguments ▸ Mockito limitations
  65. @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()
  66. @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
  67. @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
  68. @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
  69. @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
  70. @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'
 }
  71. @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'
 }
  72. @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'
 }
  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
  74. @MOLSJEROEN #DEVOXX #MOCKITO CUSTOM MATCHER - LIST CONTAINS public class

    ListContains<T> implements ArgumentMatcher<List> {
 
 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]";
 }
 }
  75. @MOLSJEROEN #DEVOXX #MOCKITO CUSTOM MATCHER - LIST CONTAINS public class

    ListContains<T> implements ArgumentMatcher<List> {
 
 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]";
 }
 }
  76. @MOLSJEROEN #DEVOXX #MOCKITO CUSTOM MATCHER - LIST CONTAINS public class

    ListContains<T> implements ArgumentMatcher<List> {
 
 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]";
 }
 }
  77. @MOLSJEROEN #DEVOXX #MOCKITO CUSTOM MATCHER - LIST CONTAINS public class

    ListContains<T> implements ArgumentMatcher<List> {
 
 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]";
 }
 }
  78. @MOLSJEROEN #DEVOXX #MOCKITO CUSTOM MATCHER - LIST CONTAINS public class

    ListContains<T> implements ArgumentMatcher<List> {
 
 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]";
 }
 }
  79. @MOLSJEROEN #DEVOXX #MOCKITO CUSTOM MATCHER - STATIC METHOD public class

    ListMatchers {
 
 @Nullable
 public static <K> List listContains(K object) {
 return argThat(new ListContains<>(object));
 }
 }
  80. @MOLSJEROEN #DEVOXX #MOCKITO CUSTOM MATCHER - STATIC METHOD public class

    ListMatchers {
 
 @Nullable
 public static <K> List listContains(K object) {
 return argThat(new ListContains<>(object));
 }
 }
  81. @MOLSJEROEN #DEVOXX #MOCKITO CUSTOM MATCHER - STATIC METHOD public class

    ListMatchers {
 
 @Nullable
 public static <K> List listContains(K object) {
 return argThat(new ListContains<>(object));
 }
 }
  82. @MOLSJEROEN #DEVOXX #MOCKITO TRADITIONAL TEST - ARGUMENTCAPTOR @Test public void

    argumentCaptorTest() throws Exception {
 User user = new User(mockWebService, USER_ID, PASSWORD);
 ArgumentCaptor<List<String>> listCaptor = ...;
 String expectedMessage = "Test message";
 
 user.sendMessage(expectedMessage);
 
 verify(mockWebService).sendMessages(listCaptor.capture());
 List<String> messages = listCaptor.getValue();
 String actualMessage = messages.get(0);
 
 assertEquals(expectedMessage, actualMessage);
 }
  83. @MOLSJEROEN #DEVOXX #MOCKITO TRADITIONAL TEST - ARGUMENTCAPTOR @Test public void

    argumentCaptorTest() throws Exception {
 User user = new User(mockWebService, USER_ID, PASSWORD);
 ArgumentCaptor<List<String>> listCaptor = ...;
 String expectedMessage = "Test message";
 
 user.sendMessage(expectedMessage);
 
 verify(mockWebService).sendMessages(listCaptor.capture());
 List<String> messages = listCaptor.getValue();
 String actualMessage = messages.get(0);
 
 assertEquals(expectedMessage, actualMessage);
 }
  84. @MOLSJEROEN #DEVOXX #MOCKITO TRADITIONAL TEST - ARGUMENTCAPTOR @Test public void

    argumentCaptorTest() throws Exception {
 User user = new User(mockWebService, USER_ID, PASSWORD);
 ArgumentCaptor<List<String>> listCaptor = ...;
 String expectedMessage = "Test message";
 
 user.sendMessage(expectedMessage);
 
 verify(mockWebService).sendMessages(listCaptor.capture());
 List<String> messages = listCaptor.getValue();
 String actualMessage = messages.get(0);
 
 assertEquals(expectedMessage, actualMessage);
 }
  85. @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));
 }
  86. @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
  87. @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
  88. @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
 }
 }
  89. @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
 }
 }
  90. @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);
 }
 }
  91. @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);
 }
 }
  92. @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);
 }
 }
  93. @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
  94. @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();
 }
 }
  95. @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();
 }
 }
  96. @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
  97. @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
 }
  98. @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";
 } 
 ... }
  99. @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";
 } 
 ... }
  100. @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
  101. @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
  102. @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
  103. @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;
 }
  104. @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();
 }
  105. @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
  106. @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”
  107. @MOLSJEROEN #DEVOXX #MOCKITO IT IS BETTER TO HAVE A SIMPLE

    TEST THAT WORKS THAN A COMPLICATED TEST THAT SEEMS TO WORK. Mockito documentation
  108. @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
  109. @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
  110. @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/