0
0
JUnittesting~15 mins

Mock objects in JUnit - Build an Automation Script

Choose your learning style9 modes available
Verify UserService calls UserRepository save method
Preconditions (2)
Step 1: Create a User object with name 'Alice' and email 'alice@example.com'
Step 2: Call UserService.createUser with the User object
Step 3: Verify that UserRepository.save was called once with the same User object
✅ Expected Result: UserRepository.save method is called exactly once with the User object passed to UserService.createUser
Automation Requirements - JUnit 5 with Mockito
Assertions Needed:
Verify UserRepository.save called once with correct User
No other interactions with UserRepository
Best Practices:
Use @Mock and @InjectMocks annotations
Use Mockito.verify for interaction verification
Keep test method focused and clear
Automated Solution
JUnit
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void testCreateUserCallsSave() {
        // Arrange
        User user = new User("Alice", "alice@example.com");

        // Act
        userService.createUser(user);

        // Assert
        verify(userRepository, times(1)).save(user);
        verifyNoMoreInteractions(userRepository);
    }
}

// Supporting classes for context
class User {
    private String name;
    private String email;

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // equals and hashCode should be overridden for correct verification
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return name.equals(user.name) && email.equals(user.email);
    }

    @Override
    public int hashCode() {
        return java.util.Objects.hash(name, email);
    }
}

interface UserRepository {
    void save(User user);
}

class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void createUser(User user) {
        userRepository.save(user);
    }
}

This test uses JUnit 5 with Mockito to check that UserService.createUser calls UserRepository.save exactly once with the correct User object.

Annotations: @Mock creates a mock UserRepository. @InjectMocks injects this mock into UserService.

Test steps: We create a User object, call createUser, then verify the mock's save method was called once with that user.

Verification: verify(userRepository, times(1)).save(user) checks the call count and argument. verifyNoMoreInteractions ensures no other calls happened.

Supporting classes: User overrides equals and hashCode so Mockito can compare objects correctly.

Common Mistakes - 4 Pitfalls
Not overriding equals and hashCode in User class
Using @Mock without @ExtendWith(MockitoExtension.class)
Verifying method call without specifying times(1)
Not verifying no more interactions
Bonus Challenge

Now add data-driven testing with 3 different User inputs to verify save is called correctly each time

Show Hint