ByteIntroduction

Getting started with Mockito

Skills:

Mockito

Objective

Get started with Mockito

Background/Recap

Software testing is essential to ensure correct working of applications. It also helps speed up the development process as the tests would let us know if changes to the program breaks something. Unit testing is a type of software testing where each smaller part of the application is tested in isolation from other components. These tests are usually run multiple times daily & that too not on the server but on the developer’s computer. Hence, unit tests have to be quick. Apart from increasing the tests time, dependencies also increase chances of a test failing even with correct logic because the test could fail due to a bug in any of the dependencies.


To not care about dependencies, we replace the original implementation of the dependency using test doubles like Mocks, Stubs, Spies. We can stub methods to return predefined values, for example, when calling methods that are not implemented yet. Mocking allows capturing interactions to the mocked objects & returns null for any calls that’s not stubbed. Spying provides similar functionality as of mocking. The difference is that for non-stubbed scenarios, the spied objects work normally.


Mockito is a Java library popularly used in testing to create test doubles.

Primary goals

  1. Understand the need for using Mockito

  2. Understand using Mockito to test predefined behaviour

  3. Understand using Mockito to simulate behaviour based on input

  4. Understand using Mockito to verify interactions with dependencies

  5. Understand common issues and tips working with Mockito

Objective

Get started with Mockito

Background/Recap

Software testing is essential to ensure correct working of applications. It also helps speed up the development process as the tests would let us know if changes to the program breaks something. Unit testing is a type of software testing where each smaller part of the application is tested in isolation from other components. These tests are usually run multiple times daily & that too not on the server but on the developer’s computer. Hence, unit tests have to be quick. Apart from increasing the tests time, dependencies also increase chances of a test failing even with correct logic because the test could fail due to a bug in any of the dependencies.


To not care about dependencies, we replace the original implementation of the dependency using test doubles like Mocks, Stubs, Spies. We can stub methods to return predefined values, for example, when calling methods that are not implemented yet. Mocking allows capturing interactions to the mocked objects & returns null for any calls that’s not stubbed. Spying provides similar functionality as of mocking. The difference is that for non-stubbed scenarios, the spied objects work normally.


Mockito is a Java library popularly used in testing to create test doubles.

Primary goals

  1. Understand the need for using Mockito

  2. Understand using Mockito to test predefined behaviour

  3. Understand using Mockito to simulate behaviour based on input

  4. Understand using Mockito to verify interactions with dependencies

  5. Understand common issues and tips working with Mockito

Download source code

  • Create ~/workspace/bytes/ directory and cd to it

mkdir -p ~/workspace/bytes/

cd ~/workspace/bytes/

  • Download the source code to the ~/workspace/bytes/ directory from here using one of the following commands:

git clone git@gitlab.crio.do:crio_bytes/me_mockito.git

git clone https://gitlab.crio.do/crio_bytes/me_mockito.git

Running Tests

See the attached video to run tests

  • From the test file, or

  • From the VS code Test window

Debugging Tests

See the attached video to debug tests

  • From the test file, or

  • From the VS code Test window

Understanding the project code

Have you come across this cool Google Maps feature where it lets you book Uber/Ola cabs directly from the Maps app itself?


Let’s check the case of Uber cabs. Uber provides REST API to avail their services from other applications. Google Maps could get a list of Uber cabs available from a source to a destination location. The API endpoint for this specific use case is - GET /v1.2/estimates/price. Similarly, there are API endpoints for other purposes like booking a cab and getting status of a ride.

image alt text

We’ll be simulating this API call using the getPriceEstimates() method in src\main\java\external\uber\ExternalUberService.java.

image alt text

Much like most REST APIs, the response is in JSON format. The JSON response is read as Java objects or objects of the type PriceEstimate to be more precise. You’ll see that each of the keys in the JSON data has a corresponding field in the PriceEstimate class to which value of the key gets mapped to.

image alt text

To summarize the project files:

  • All classes contain getter and setter methods for their fields

  • src\main\java\external\uber\ExternalUberService.java - contains methods related to the Uber cab service

    • getPriceEstimates() - fetches info on Uber cabs available for a journey using Uber API

    • buildPriceEstimateBaseUrl() - builds the Uber API url from start and end location coordinates

  • src\main\java\external\uber\model\PriceEstimate.java - used to deserialize API response in JSON format to Java object

  • src\main\java\internal\helper\GoogleMapsHelper.java - contains contract for helper methods in the form of interface

    • isValidLocations() - check if the input start and end location coordinates are valid

    • makeUberPayment - make payment for a Uber cab

  • src\test\java\external\uber\ExternalUberServiceTest.java - contains the unit tests

  • src\test\resources\price_estimate.json - sample Uber API response

The need for Mockito

Testing code concerned with Uber API in Google Maps without mocking leads to:

  • Slows the unit tests as it involves network calls to Uber servers

  • Running the unit tests can become expensive if any of these APIs are rate-limited or charged by Uber

  • Unit tests cannot be run if the Uber API servers are temporarily down


Let’s check on some scenarios where Mockito helps in more detail

Unit testing even when dependencies aren’t available

Quite often, different components of a project will be worked on by developers across multiple teams. There will be a contract pre-defined in these scenarios, mostly in the form of interfaces specifying the behaviour of different methods. Your code will be using the components others are working on.


Our getPriceEstimate() method in the ExternalUberService class uses the isValidLocations() method of GoogleMapsHelper. GoogleMapsHelper is an interface containing method contracts being worked on by a different team yet to be implemented. Should you wait for the other team to complete their code to start unit testing your implementation?



public interface GoogleMapsHelper {

  /**

   * Validates the correctness of the starting and ending location coordinates

   *

   * @param startLatitude of type Double.

   * @param startLongitude of type Double.

   * @param endLatitude of type Double.

   * @param endLongitude of type Double.

   * @return true if coordinates given are all valid,

   * false if any of the coordinate values are invalid

   * Valid Latitude range -> -90 to +90

   * Valid Longitude range -> -180 to +180

   */

  public boolean isValidLocations(Double startLatitude, Double startLongitude,

      Double endLatitude, Double endLongitude);


  /**

   * Makes payment for the Uber cab booked via Google Maps

   *

   * @param tripID of type String

   * @param otp of type String

   * @return true if the payment was success,

   * false if the payment failed

   */

  public boolean makeUberPayment(String tripID, String otp);

}

Isolate your unit tests from dependencies

Unit testing by definition should only be testing for a specific unit or functionality. Let’s say we are unit testing the getPriceEstimates() method. Now, what happens if the buildPriceEstimateBaseUrl() method has a bug?


Yeah, the unit test for getPriceEstimates() will also fail. This is not a preferable behaviour. In large projects with multiple dependencies, it’ll be hard to pinpoint the cause of unit test failure if the unit tests aren’t isolated from the dependencies. Also, as buildPriceEstimateBaseUrl() will be unit tested separately, it’s safe to assume that it works as expected when testing getPriceEstimates().


How would you isolate the dependencies when unit testing?

image alt text

Testing for behavior that doesn’t exist/cannot be created today

It’s critical that our code be tested to ensure its correctness as well as to check how it handles irregularities. What would happen if Uber API response structure got changed in a future release or a bug introduced returns an empty response occasionally?

image alt text


To check how our code behaves in these cases, we’ll have to get these exact responses back from the Uber API server. But, how would you do that? These are scenarios we are anticipating and don't happen today.


Mockito can be used to return preset responses to deal with all the 3 scenarios we discussed without making any changes to the implementation.

Mocking with Mockito

ExternalUberServiceTest class has a getPriceEstimateBaseUrlTest() method. This is a JUnit only unit test for the buildPriceEstimateBaseUrl() method and doesn’t involve Mockito. Run it and you’ll see it pass.


We’ll be writing unit tests for the getPriceEstimates() method. The getPriceEstimates() method should return an empty array if any of the input coordinates are invalid. The getPriceEstimatesWithoutMockTest() test checks for this case.


public void getPriceEstimatesWithoutMockTest() {

    // Setup

    Double startLatitude = 137.775231;

    Double startLongitude = -122.418075;

    Double endLatitude = 37.775241;

    Double endLongitude = -122.518075;

    

    ExternalUberService externalUberService = new ExternalUberService();


    // Get output of the method under test

    PriceEstimate[] actualPriceEstimates = externalUberService.getPriceEstimates(

      startLatitude, startLongitude, endLatitude, endLongitude);


    // Check if the returned value matches expected value

    int expectedLength = 0;

    assertEquals(expectedLength, actualPriceEstimates.length);

  }

TODO -

  • Run getPriceEstimatesWithoutMockTest(). Does the test pass?

  • Check the error response. Why do you think the test is failing?


You’d have found that the test failed.

image alt text

The test report is mentioning that the googleMapsHelper field is null. You’d recall isValidLocations() is an abstract method in the GoogleMapsHelper interface. (Comment out getPriceEstimatesWithoutMockTest(), we’ll write a different test that works)

image alt text

Dependencies for the Code Under Test

To test getPriceEstimates(), we’ll mock GoogleMapsHelper and set the googleMapsHelper field of the ExternalUberService instance as this mock object in the test. This allows you to pre-set an output which is returned when isValidLocations() is called with a specific input from the test. By mocking, we’re basically removing the dependency of the Code Under Test (getPriceEstimates()) on isValidLocations()

image alt text

Replacing dependency with a Mock

The getPriceEstimatesReturnsEmptyArrayOnInvalidStartLatitudeTest() test checks if the getPriceEstimates() method returns an empty array when the starting location latitude is invalid. You can see the valid range of latitude is from -90 to +90 in the GoogleMapsHelper contract. The starting location latitude given in the test doesn’t fall in this interval.


Below is the test code


// 1

@Mock

private GoogleMapsHelper googleMapsHelperMock;


public void getPriceEstimatesReturnsEmptyArrayOnInvalidStartLatitudeTest() {

    // 2. Setup

    Double startLatitude = 137.775231;

    Double startLongitude = -122.418075;

    Double endLatitude = 37.775241;

    Double endLongitude = -122.518075;

    

    // 3. 

    ExternalUberService externalUberService = new ExternalUberService();

    externalUberService.setGoogleMapsHelper(googleMapsHelperMock);


    // 4. Setup mock to return preset value of false

    // when startLatitude parameter is 137.775231

    when(googleMapsHelperMock.isValidLocations(eq(137.775231), anyDouble(), anyDouble(), anyDouble()))

      .thenReturn(false);


    // 5. Get output of the method under test

    PriceEstimate[] actualPriceEstimates = externalUberService.getPriceEstimates(

      startLatitude, startLongitude, endLatitude, endLongitude);


    // 6. Check if the returned value matches expected value

    int expectedLength = 0;

    assertEquals(expectedLength, actualPriceEstimates.length);

  }

  1. The @Mock annotation is used to create a Mock object of type GoogleMapsHelper, googleMapsHelperMock (this is done at the class level)

  2. The input coordinate values are initialized

  3. Created an ExternalUberService object and set its googleMapsHelper field value to googleMapsHelperMock

  4. Use Mockito when().thenReturn() statement to return false when the isValidLocations() method of the googleMapsHelperMock object is called with the the startLatitude value of 137.775231 and any Double value for other parameters. eq() and anyDouble() are Mockito argument matchers. anyDouble() matches with any Double value while eq() requires the exact value inside it to get matched.

  5. The function to test is called

  6. Validate if the output is as expected


We’ve created the Mock object for googleMapsHelper and set it to return false when called with the correct arguments. The test should pass now, right? Try running it.

image alt text

It’s still failing!


To allow the JUnit test class to support Mocks, we need to register the Mockito extension for the test class. @ExtendWith(MockitoExtension.class) annotation does this.


@ExtendWith(MockitoExtension.class)

public class ExternalUberServiceTest {

The test will pass now.


Confused which object(s) to Mock and what to return? Use this framework to your aid


Code Under Test: ExternalUberService.getPriceEstimates()

Test case: Check if ExternalUberService.getPriceEstimates() returns empty

array on invalid latitude for start location

Dependency Layer/Function:

  1. googleMapsHelper.isValidLocation(String startLatitude, String startLongitude,

    String endLatitude, String endLongitude);

Mock Setup:

  - Function to mock: googleMapsHelper.isValidLocation()

    - Input to mock: (some invalid start latitude, any start longitude, any end

        latitude, any end longitude)

    - Pre-set output from mock: false

Test Input: externalUberService.getPriceEstimates()(parameters should be

inline with your mock setup)

Expected Test Output: Empty price estimate array

image alt text

Feel free to add more tests to check if getPriceEstimates() return an empty array when the other coordinates (startLongitude, endLatitude, endLongitude) are invalid

Curious Cats

  • We used eq(137.775231) inside the when().thenReturn() statement for getPriceEstimatesReturnsEmptyArrayOnInvalidStartLatitudeTest(). Wouldn’t just 137.775231 suffice? Can you verify that?

  • Similar to when().doReturn(), Mockito provides another statement doReturn().when(). Can you check its usage & re-write the stubbings using doReturn().when()?

Controlling the output of Mocks

Let’s now test getPriceEstimates() to return the API response as PriceEstimate objects on a valid input coordinates and successful API call. The getPriceEstimatesValidLocationReturnsPriceEstimatesTest() does this. A mock object was used earlier for googleMapsHelper to avoid the test’s dependency on it. Similarly to make the test independent of the API response, the restTemplate object (which fetches the API response) will also be mocked.


ExternalUberService externalUberService = new ExternalUberService();

externalUberService.setGoogleMapsHelper(googleMapsHelperMock);

externalUberService.setRestTemplate(restTemplateMock);

TODO - Complete the below framework for this test case and answer the first question at the end of this milestone


Code Under Test: 

Test case: 

Dependency Layer/Function:

  1.  

  2. 

Mock Setup:

  - Function to mock: 

    - Input to mock: 

    - Pre-set output from mock: 

  - Function to mock: 

    - Input to mock: 

    - Pre-set output from mock: 

Test Input: 

Expected Test Output: 

image alt text

Replacing dependencies with Mocks
  1. The isValidLocations() call is set to return true

  2. The getForObject() call returns data read from the price_estimate.json file using loadPriceEstimateList() method in the test


Earlier, getPriceEstimatesReturnsEmptyArrayOnInvalidStartLatitudeTest() was used to test the getPriceEstimates() method. If you check the test, we were using the when().thenReturn() statement to hardcode the return value when the isValidLocations() method was called. Let’s see how to use the actual parameter values to isValidLocations() for deciding what to return.


The current test uses Mockito Answer interface and doAnswer().when() method for this.


Answer<Boolean> validity = new Answer<Boolean>() {

      public Boolean answer(InvocationOnMock invocation)

          throws Throwable {

          // Get the first argument to the invoked method

          Double startLatitude = invocation.getArgument(0);

        

          // Valid latitude is in -90 to +90

          if (Math.abs(startLatitude) <= 90 ) {

            return true;

          } else {

            return false;

          }

      }

    };


// Return the value of `validity` when the method of the Mock is invoked

doAnswer(validity).when(googleMapsHelperMock).isValidLocations(eq(37.775231), anyDouble(), anyDouble(), anyDouble());

Some points to understand Answer:

  1. Answer is a generic interface which is why we’re passing the return type Boolean all over the definitions

  2. We have to implement the answer() method which takes in a single fixed argument of type InvocationOnMock. The InvocationOnMock argument acts as a placeholder for the called mock method and thus we can use it to fetch the parameters with which the method was called. This is done using getArgument()


In addition to checking the length of the array returned, the test checks for the output array content as well.


assertEquals(3, actualPriceEstimates.length);

assertEquals("₹110-140", actualPriceEstimates[0].getEstimate());

assertEquals("₹110-130", actualPriceEstimates[1].getEstimate());

assertEquals("₹210", actualPriceEstimates[2].getEstimate());

Run the getPriceEstimatesReturnsEmptyArrayOnInvalidStartLatitudeTest() test, it should pass.

Curious Cats

  • What does the unstubbed methods of a mock object return? Is it always null or does it depend on the method’s return type?

Automating Mocks assignments

Each of the tests were initialising an ExternalUberService object till now. Also, we’ve been using the setter method of the ExternalUberService class to assign its googleMapsHelper field as the Mock object.


ExternalUberService externalUberService = new ExternalUberService();

externalUberService.setGoogleMapsHelper(googleMapsHelperMock);

externalUberService.setRestTemplate(restTemplateMock);

TODO -

  • Comment out the above lines in getPriceEstimatesValidLocationReturnsPriceEstimatesTest() and run the test

  • Read and understand the error


The test fails as we haven’t initialized externalUberService.

image alt text

We can resolve this error for now by initialising the externalUberService at the class-level.

Set the below line at the start of ExternalUberServiceTest


private ExternalUberService externalUberService;

to


private ExternalUberService externalUberService = new ExternalUberService();

TODO - Run the test again


Now, the test will fail again as expected due to invoking the googleMapsHelper field which is null as of now.

image alt text

Mockito @InjectMocks annotation can be used to automatically initialize the class we’re testing as well as to inject the Mock objects it requires. Add the @InjectMocks annotation to externalUberService field and remove the initialization.


@InjectMocks

private ExternalUberService externalUberService;

Run getPriceEstimatesValidLocationReturnsPriceEstimatesTest() again, it should pass now. You can remove similar lines from other tests as well and see that they run successfully as well.


Now, how did Mockito "inject" the mocks to externalUberService?


Set breakpoints inside setRestTemplate() and setGoogleMapsHelper() methods in ExternalUberService.

image alt text

Start the getPriceEstimatesValidLocationReturnsPriceEstimatesTest() test in debug mode. What do you find?


The debugger will stop inside the setGoogleMapsHelper() method. Similarly, it will reach inside the setRestTemplate() method as well. This is how @InjectMocks is setting the Mock objects without us explicitly calling the setter method in each individual test

image alt text

Curious Cats

  • Are all the Mocked objects injected always or only the ones required for the test. For example, the getPriceEstimateBaseUrlTest() doesn’t require any of the mocks. Do the mocks get injected when this test only is run?

Mockito - verify and ArgumentCaptor

Till now, we’ve been testing the getPriceEstimate() method for only the output it returned. How would we validate the correct methods are called with correct arguments?


TODO - Uncomment the getPriceEstimatesWithBug() method in ExternalUberService class.


You’ll be able to find that the arguments to isValidLocations() are ordered incorrectly. Both the latitude values are coming first instead of latitude and longitude of the starting location first.


if (!googleMapsHelper.isValidLocations(startLatitude, endLatitude, startLongitude, endLongitude)) {

TODO - Uncomment the getPriceEstimatesWithBugTest() method.


This is the exact test as getPriceEstimatesValidLocationReturnsPriceEstimatesTest(). The difference being the code under test now is getPriceEstimatesWithBug() instead of getPriceEstimates(). Run the test and see if it fails.


No, right?


Mockito provides a verify() statement to check if a Mock is being interacted with during the test with the correct set of arguments.Add the below line of code to the end of the test.


verify(googleMapsHelperMock).isValidLocations(startLatitude, startLongitude, endLatitude, endLongitude);

TODO -

  1. Run the test again and see it failing.

  2. Read through the error and understand what happened

  3. Check the error trace to find the line of code in the test which threw it

image alt text

The test fails on the verify() call and error message says that the Mock was expecting an invocation with arguments, 37.775231, -122.418075, 37.775241, -122.518075 but received 37.775231, 37.775241, -122.418075, -122.518075.


Correct the ordering of isValidLocations() arguments and ensure the test passes.


Mockito ArgumentCaptor is used to capture the arguments by which method of a mocked object is called.


ArgumentCaptor<String> quantityCaptor = ArgumentCaptor.forClass(String.class);

verify(restTemplateMock).getForObject(quantityCaptor.capture(), eq(PriceEstimate[].class));

  1. First, initialize a ArgumentCaptor object of the data type same as the argument we need to capture

  2. Use the capture() method when calling verify() to capture the argument


The captured value now can be used to check if it matches the expected one


String actualUrl = quantityCaptor.getValue();

assertEquals(url, actualUrl);

Curious Cats

  • Keeping in mind future enhancements, you need to ensure the Uber API is getting called at most twice per getPriceEstimates() call. Does the test fail now if the getPriceEstimates() implementation contains multiple restTemplate.getForObject() calls? How would you test for this scenario?

Checking if your Mock is getting called


Let’s see how to check if the Mock used in a test is actually getting called.


TODO -

  • Put a breakpoint in the GoogleMapsHelper interface on the isValidLocations() method.

  • Start the getPriceEstimatesValidLocationReturnsPriceEstimatesTest() test in debug mode. Does the control go to GoogleMapsHelper?


You’ll find that the debugger doesn’t stop at the breakpoint in GoogleMapsHelper. The test will run to completion (if you don’t have breakpoints set anywhere else)



TODO -

  • Put a breakpoint on the isValidLocations() method call in the getPriceEstimates()

  • Start the getPriceEstimatesValidLocationReturnsPriceEstimatesTest() test in debug mode.

  • Hover over the googleMapsHelper field or use the Debug console to print it out. Is it of type GoogleMapsHelper?


You’ll find that the googleMapsHelper instance is Mock version of GoogleMapsHelper

image alt text

Initializing dependencies correctly

FInd out where in ExternalUberService class we are initialising the restTemplate and googleMapsHelper fields.


No where in the class will you be able to find out these objects instantiated using the new keyword. We’re using the Spring framework’s @Autowired annotation on both of these fields. This way we’re outsourcing to Spring, the responsibility of instantiating these whenever the program is run. This also works in harmony with Mockito. Let’s see what happens to the tests if we initialize these using the new keyword.


TODO -

  • Add the below line of code before the restTemplate.getForObject() call in getPriceEstimates()

restTemplate = new RestTemplate();

  • Put a breakpoint

    • Inside the setRestTemplate() method

    • On the line where restTemplate.getForObject() is called inside getPriceEstimates()

  • Start the getPriceEstimatesValidLocationReturnsPriceEstimatesTest() test in debug mode.

  • Is restTemplate a Mock object or real RestTemplate object when

    • When the debugger stops inside setRestTemplate

    • When the debugger stops inside the getPriceEstimates() method


You’d have found that restTemplate was set to a Mock object initially in the setter but got overridden as it was re-initialized inside the getPriceEstimates() method. If you ran the test to completion, the error will tell you about an authorization exception. This happened because the Uber API got called actually which requires an authentication token to be sent as well.

Debugging your way out of Mockito setup error

Mockito can fail due to subtle differences in the Mock setup and it can become hard to debug the error by just glancing through the code.

TODO -

  • Uncomment the mockitoSetupErrorTest() test and run it

  • Run the test and try to understand the error.

  • To debug your way out of it, comment out the current when().thenReturn() statement and start with more general arguments

    • Use when(googleMapsHelperMock.isValidLocations(any(), any(), any(), any())) .thenReturn(false);. Does the test pass now? Passing test means the Mock setup was called

    • Use Usewhen(googleMapsHelperMock.isValidLocations(anyDouble(), anyDouble(), anyDouble(), anyDouble())).thenReturn(false)`. Does the test pass now?

    • Similarly, try to go on being more and more specific to find out the issue

Dealing with UnnecessaryStubbingException

Mockito throws the UnnecessaryStubbingException if the setup using when().thenReturn() doesn’t get invoked during the test. This can be a desirable behaviour from the point of view of the developer because if we used a when().thenReturn() in the test, it’s either

  • we wanted it to get invoked. Not getting invoked would mean there’s some error, or

  • the stubbing isn’t required in the first place


TODO -

  • Uncomment the unnecessaryStubbingExceptionTest() test and run it

  • You’ll get the error report with the UnnecessaryStubbingException. Read through it to understand the issue

  • What and why do you think the error was thrown?

image alt text

The test is for the buildPriceEstimateBaseUrl(). The test has stubbed the isValidLocations() method but the method under test doesn’t use the isValidLocations() method. Removing the when().thenReturn() method solves the problem here.

Summary

  • Test doubles are used to replace original implementation for the purpose of testing. They include mocks, stubs and spies.

  • Using Mockito to deal with dependencies in unit tests can

    • Reduce time taken to run unit tests by removing expensive I/O operations like network requests, database operations or file I/O

    • Avoid cost for running unit test by not making API calls or requests that are paid

    • Isolate unit tests from dependencies

    • Allow to test for conditions that doesn’t exist or cannot be created otherwise.

  • Mockito dictionary

    • @ExtendWith(MockitoExtension.class) registers the test class to support Mockito

    • @Mock creates a mock of an object

    • @InjectMocks injects the dependent mock objects to the object annotated with it

    • when().thenReturn() stubs methods of mocked objects with values to return when called with appropriate arguments

    • doAnswer() stubs method based on the argument value to the mock method

    • verify() validates that the mock was interacted with during the course of the test

    • ArgumentCaptor can capture arguments by which the mock methods are called during the test

  • Though Mockito is tricky to learn and get right, the errors usually contain good debugging information. Try to understand what the error is saying to debug more efficiently.

  • Find the solutions to the Curious Cats questions here

  • Further Reading

Newfound Superpowers

  • Knowledge of the Mockito framework.

Now you can

  • Write more efficient and complex unit tests using Mockito

  • Write unit tests that are independent of dependencies

  • Write unit tests to test for more vivid behaviours