In this section, we will explore how to verify interactions with mocks using Mockito in JUnit. Verifying interactions is crucial to ensure that your code behaves as expected, especially when dealing with dependencies and side effects.
Key Concepts
- Mocking: Creating a mock object to simulate the behavior of real objects.
- Verification: Checking if certain methods were called on the mock object with the expected arguments.
Why Verify Interactions?
Verifying interactions helps to:
- Ensure that the correct methods are called.
- Validate the sequence of method calls.
- Confirm that no unexpected interactions occur.
Setting Up Mockito
Before we dive into verifying interactions, ensure you have Mockito set up in your project. Add the following dependencies to your pom.xml
if you are using Maven:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.11.2</version> <scope>test</scope> </dependency>
Basic Verification
Example
Let's start with a simple example. Suppose we have a Calculator
class with a method add
:
We want to verify that the add
method is called with specific arguments.
Test Case
import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; public class CalculatorTest { @Test public void testAddMethodCalled() { // Create a mock of Calculator Calculator calculator = mock(Calculator.class); // Use the mock object calculator.add(10, 20); // Verify that the add method was called with arguments 10 and 20 verify(calculator).add(10, 20); } }
Explanation
- Creating a Mock:
Calculator calculator = mock(Calculator.class);
- This creates a mock object of the
Calculator
class.
- This creates a mock object of the
- Using the Mock:
calculator.add(10, 20);
- We call the
add
method on the mock object.
- We call the
- Verifying the Interaction:
verify(calculator).add(10, 20);
- This verifies that the
add
method was called with the arguments10
and20
.
- This verifies that the
Advanced Verification
Verifying Call Count
You can also verify how many times a method was called:
Verifying No Interactions
To ensure that no interactions have occurred with the mock:
Verifying No More Interactions
To verify that no other interactions have occurred after the specified calls:
Verifying in Order
To verify that methods were called in a specific order:
import static org.mockito.Mockito.*; import org.mockito.InOrder; import org.junit.jupiter.api.Test; public class CalculatorTest { @Test public void testMethodCallOrder() { Calculator calculator = mock(Calculator.class); // Use the mock object calculator.add(10, 20); calculator.add(30, 40); // Create an InOrder verifier for the mock InOrder inOrder = inOrder(calculator); // Verify the order of method calls inOrder.verify(calculator).add(10, 20); inOrder.verify(calculator).add(30, 40); } }
Practical Exercise
Exercise
- Create a
UserService
class with a methodcreateUser(String username)
. - Create a test case to verify that the
createUser
method is called with the argument"john_doe"
.
Solution
public class UserService { public void createUser(String username) { // Logic to create a user } } import static org.mockito.Mockito.*; import org.junit.jupiter.api.Test; public class UserServiceTest { @Test public void testCreateUserCalled() { // Create a mock of UserService UserService userService = mock(UserService.class); // Use the mock object userService.createUser("john_doe"); // Verify that the createUser method was called with argument "john_doe" verify(userService).createUser("john_doe"); } }
Common Mistakes and Tips
- Forgetting to Use
verify
: Always useverify
to check interactions. - Incorrect Argument Matching: Ensure the arguments in
verify
match exactly with the method call. - Overusing Verification: Verify only necessary interactions to keep tests maintainable.
Conclusion
In this section, we learned how to verify interactions with mocks using Mockito in JUnit. We covered basic verification, advanced verification techniques, and common mistakes. Verifying interactions is a powerful tool to ensure your code behaves as expected, especially when dealing with dependencies. In the next module, we will explore advanced JUnit features such as timeouts and exception testing.
JUnit Course
Module 1: Introduction to JUnit
Module 2: Basic JUnit Annotations
- Understanding @Test
- Using @Before and @After
- Using @BeforeClass and @AfterClass
- Ignoring Tests with @Ignore
Module 3: Assertions in JUnit
Module 4: Parameterized Tests
- Introduction to Parameterized Tests
- Creating Parameterized Tests
- Using @ParameterizedTest
- Custom Parameterized Tests
Module 5: Test Suites
Module 6: Mocking with JUnit
Module 7: Advanced JUnit Features
Module 8: Best Practices and Tips
- Writing Effective Tests
- Organizing Test Code
- Test-Driven Development (TDD)
- Continuous Integration with JUnit