Mockito


Spring Boot অ্যাপ্লিকেশন ডেভেলপ করার সময় টেস্টিং একটি গুরুত্বপূর্ণ অংশ। Mockito হলো একটি জনপ্রিয় Java mocking framework, যা দিয়ে আমরা dependency গুলোকে “mock” করতে পারি, অর্থাৎ আসল অবজেক্ট ছাড়াই unit test চালাতে পারি।


Mockito কী?

Mockito এমন একটি লাইব্রেরি, যা আমাদের কোডের dependency বা external call গুলোকে simulate (mock) করে দেয়।

এতে আমরা মূল লজিক টেস্ট করতে পারি ডাটাবেজ বা নেটওয়ার্কে না গিয়েই। উদাহরণ:

ধরো, UserService ক্লাস UserRepository এর উপর নির্ভরশীল।
Unit test-এ আমরা চাই না আসল ডাটাবেজে সংযোগ হোক —
বরং UserRepository-কে mock করে নির্দিষ্ট রেসপন্স ফিরিয়ে দিতে পারি।


প্রয়োজনীয় Dependency

pom.xml ফাইলে নিচের dependency যোগ করো:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Spring Boot এর spring-boot-starter-test প্যাকেজে আগে থেকেই JUnit, Mockito, Hamcrest, AssertJ অন্তর্ভুক্ত থাকে।


উদাহরণ প্রজেক্ট স্ট্রাকচার

src
 └── main
     └── java/com/example/mockito
         ├── User.java
         ├── UserRepository.java
         └── UserService.java
 └── test
     └── java/com/example/mockito
         └── UserServiceTest.java


User Entity

public class User {
    private Long id;
    private String name;

    // Constructors, getters, setters
}


Repository Interface

public interface UserRepository {
    User findById(Long id);
    void save(User user);
}


Service Layer

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public String getUserName(Long id) {
        User user = userRepository.findById(id);
        if (user == null) {
            throw new RuntimeException("User not found!");
        }
        return user.getName();
    }

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


Mockito দিয়ে Unit Test

এখন আমরা UserServiceTest তৈরি করব যেখানে আসল UserRepository এর পরিবর্তে mock ব্যবহার করবো।

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void shouldReturnUserName_WhenUserExists() {
        // Arrange
        User mockUser = new User();
        mockUser.setId(1L);
        mockUser.setName("Maruf");

        when(userRepository.findById(1L)).thenReturn(mockUser);

        // Act
        String name = userService.getUserName(1L);

        // Assert
        assertEquals("Maruf", name);
        verify(userRepository, times(1)).findById(1L);
    }

    @Test
    void shouldThrowException_WhenUserNotFound() {
        when(userRepository.findById(2L)).thenReturn(null);

        assertThrows(RuntimeException.class, () -> userService.getUserName(2L));
        verify(userRepository, times(1)).findById(2L);
    }
}


এখানে কী ঘটছে

Annotation / Method কাজ
@Mock Dependency এর জন্য fake/mock অবজেক্ট তৈরি করে।
@InjectMocks Mock dependency গুলোকে service ক্লাসে inject করে।
@ExtendWith(MockitoExtension.class) Mockito কে JUnit 5 এর সাথে ইন্টিগ্রেট করে।
when(...).thenReturn(...) Mock অবজেক্টের expected behavior সেট করে।
verify(...) কোনো method নির্দিষ্ট সংখ্যক বার কল হয়েছে কিনা যাচাই করে।


BDD Style Mockito (Behavior Driven Development)

Mockito দিয়ে আমরা BDD স্টাইলেও টেস্ট লিখতে পারি:

import static org.mockito.BDDMockito.*;

@Test
void shouldReturnUserUsingBDD() {
    // Given
    User user = new User();
    user.setId(5L);
    user.setName("Rihan");
    given(userRepository.findById(5L)).willReturn(user);

    // When
    String result = userService.getUserName(5L);

    // Then
    then(userRepository).should(times(1)).findById(5L);
    assertEquals("Rihan", result);
}


ArgumentCaptor ব্যবহার

Mockito এর আরেকটি শক্তিশালী ফিচার হলো ArgumentCaptor,
যা দিয়ে আমরা mock method এ পাস করা আর্গুমেন্ট ক্যাপচার করতে পারি।

@Captor
private ArgumentCaptor<User> userCaptor;

@Test
void shouldCaptureUserArgument() {
    User user = new User();
    user.setName("Niham");

    userService.registerUser(user);

    verify(userRepository).save(userCaptor.capture());
    assertEquals("Niham", userCaptor.getValue().getName());
}


Mockito + Spring Boot Context

যদি তুমি পুরো Spring Context সহ টেস্ট করতে চাও (Integration Test এর কাছাকাছি),
তাহলে ব্যবহার করতে পারো @SpringBootTest@MockBean:

@SpringBootTest
class UserServiceSpringBootTest {

    @MockBean
    private UserRepository userRepository;

    @Autowired
    private UserService userService;

    @Test
    void testUserServiceWithMockBean() {
        when(userRepository.findById(1L)).thenReturn(new User(1L, "Arni"));
        assertEquals("Arni", userService.getUserName(1L));
    }
}

@MockBean Spring Context এর মধ্যে bean override করে mock object inject করে দেয়।


Mockito Best Practices

- Unit test সবসময় ছোট ও নির্দিষ্ট behavior টেস্ট করো
- Mock শুধুমাত্র external dependency এর জন্য ব্যবহার করো
- Verify statement এ times(1) বা never() ব্যবহার করো
- Exception test এর জন্য assertThrows ব্যবহার করো
- Integration Test এর জন্য @MockBean ব্যবহার করো, pure Unit Test এর জন্য @Mock