Mockito trong Spring Boot là gì ?
NỘI DUNG BÀI VIẾT
JUnit là một framework dùng cho việc tạo các test case để kiểm thử các method của các đối tượng trong chương trình Java. Nó giúp cho chúng ta có thể đảm bảo đoạn code mà chúng ta viết ra chính xác với những gì chúng ta muốn. Trong nhiều trường hợp, phương thức cần test của chúng ta gọi đến nhiều phương thức, service khác mà các phương thức này chưa được cài đặt (implement) hoặc tốn nhiều chi phí để thực thi test nhiều lần. Để đảm bảo unit test không phụ thuộc vào nhau, mỗi unit test độc lập được thực thi đúng, chúng ta phải giả định rằng các phương thức được gọi đến đang xử lý đúng. Mockito giúp ta giả lập kết quả của các phương thức liên quan để tập trung viết test cho phương thức hiện tại.
1. Mokito là gì?
Mockito là một framework hỗ trợ tạo unit test bằng cách sử dụng các đối tượng giả (Mock hay TestDouble) theo cách dễ sử dụng mà không tạo ra “nhiễu” từ các tương tác không liên quan.
Một số thuận lợi khi sử dụng Mockito:
- Đơn giản: dễ dàng tạo các đối tượng giả và giả lập kết quả, hành vi test.
- Số lượng API của Mockito không nhiều, nhưng đáp ứng đầy đủ các yêu cầu để giả lập các hành vi test.
- Tập trung vào test các hành vi cụ thể, giảm thiểu các phiền nhiễu từ các tương tác không liên quan.
2. Phân loại Mock/ Test Double
Có nhiều trường hợp sử dụng các đối tượng giả, chúng ta có thể phân loại chúng như sau:
- Dummy object là các đối tượng được di chuyển khắp nơi nhưng không bao được sử dụng thật sự. Thường chúng chỉ được sử dụng để truyền danh sách tham số.
- Fake object là các đối tượng thật đã được cài đặt một cách đầy đủ, nhưng thường được sử dụng trong môi trường test, không phù hợp cho môi trường thật.
- Stub object là một chương trình hoặc thành phần giả lập dùng để kiểm thử, nó cung cấp câu trả lời cho các cuộc gọi trong khi kiểm thử. Thông thường nó không đáp lại bất kỳ thứ gì ngoài những gì đã được lập trình cho kiểm thử.
- Mock object (MO) là một đối tượng, dùng để giả lập hành vi của các class bên ngoài để thực hiện hành vi mà chúng ta mong muốn. Những giả lập này do chúng ta quản lý nên nó đảm bảo chất lượng của những đoạn code mà chúng ta đang viết Unit Test.
- Spy object : là một trường hợp đặc biệt của Stub và Mock, nó có thể gọi thực sự behavior của dependency hoặc mock một số behavior nếu cần.
3. Cài đặt Mockito
Để sử dụng Mockito chúng ta cần thêm thư viện này vào project. Với project maven, chúng ta mở file pom.xml và thêm khai báo sau:
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.25.1</version>
<scope>test</scope>
</dependency>
Code language: HTML, XML (xml)
Thêm khai báo thư viện JUnit 5 (nếu cần):
<!-- https://mvnrepository.com/artifact/org.mockito/junit-jupiter -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>junit-jupiter</artifactId>
<version>2.20.0</version>
</dependency>
Code language: HTML, XML (xml)
4. Ví dụ sử dụng Mockito với JUnit Test
Giả sử chương trình của chúng ta được chia thành 2 lớp: UserDao và UserService.
- Lớp UserDao thực hiện tạo một user với email được cung cấp vào database và trả về kết quả 1 nếu thêm thành công, ngược lại trả về 0 (trường hợp email đã tồn tại).
- Lớp UserService nhận yêu cầu từ ứng dụng, sau đó sẽ gọi UserDao để lưu vào database, nếu thêm thành công sẽ thực hiện một số logic như gửi mail và thông báo kết quả về cho người dùng. Trường hợp thêm thất bại sẽ hiển thị một thông báo lỗi.
Mỗi lớp trên được chia cho 2 developer khác nhau cùng thực hiện song song. Để đảm bảo code của mỗi class được thực thi đúng, chúng ta sẽ tiến hành viết Unit test cho nó. Lớp Service muốn viết Unit test được cần phải chờ lớp DAO hoàn thành. Tuy nhiên, điều này không cần thiết và không đúng cho Unit Test. Để tránh phục thuộc lẫn nhau và dễ dàng viết Unit Test, chúng ta sẽ sử dụng Mockito để giả định rằng các behavior của DAO đã thực hiện đúng và chúng ta chỉ việc kiểm thử logic của Service ứng với từng kết quả trả về của DAO.
Chương trình của chúng ta như sau:
UserDao.java
package com.gpcoder.mockito;
public interface UserService {
String createUser(String email);
}
Code language: PHP (php)
UserService.java
package com.gpcoder.mockito;
public interface UserService {
String createUser(String email);
}
Code language: PHP (php)
UserServiceImpl.java
package com.gpcoder.mockito;
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public String createUser(String email) {
boolean result = userDao.createUser(email);
if (result) {
// Send an email verify ...
// Show a success message to end user ...
return "SUCCESS";
}
// Send an error message to end user ...
return "FAILED";
}
}
Code language: PHP (php)
UserServiceImplTest.java
package com.gpcoder.mockito;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
// @RunWith attaches a runner with the test class to initialize the mock data
@RunWith(MockitoJUnitRunner.class)
public class UserServiceImplTest {
// Create a mock object
@Mock
private UserDao userDao;
private UserService userService;
@Before
public void setUp() {
userService = new UserServiceImpl(userDao);
}
@Test
public void createUser_WhenEmailExisted_ReturnFailed() {
// Define return value for method createUser()
Mockito.when(userDao.createUser("[email protected]")).thenReturn(false);
// Use mock in test
Assert.assertEquals("FAILED", userService.createUser("[email protected]"));
}
@Test
public void createUser_WhenEmailNotExisted_ReturnSuccess() {
// Define return value for method createUser()
Mockito.when(userDao.createUser("[email protected]")).thenReturn(true);
// Use mock in test
Assert.assertEquals("SUCCESS", userService.createUser("[email protected]"));
}
}
Code language: JavaScript (javascript)
Để dễ hiểu ví dụ trên, chúng ta sẽ cùng xem lại từng bước sử dụng Mockito ở class Test:
- Đầu tiên, chúng ta đánh dấu @RunWith(MockitoJUnitRunner.class) để Mockito xử lý các Annotation của Mockito được áp dụng trong class test này.
- Một Annotation @Mock được sử dụng để tạo một mock object và inject cho field này.
- Sử dụng phương thức Mockito.when(T methodCall): dùng để giả lập một lời gọi hàm nào đó được sử dụng bên trong method đang được kiểm thử. Phương thức này thường đi kèm với thenReturn(), thenAnswer(), thenThrow() để chỉ định kết quả trả về. Trong ví dụ này, chúng ta sử dụng thenReturn() để trả về kết quả 0 và 1, ứng với từng trường hợp trả về của DAO.
Kết luận
Trên đây là một số thông tin cơ bản về Mockito. Trong các bài viết tiếp theo chúng ta sẽ cùng tìm hiểu chi tiết các phương thức được hỗ trợ trong Mockito và các ví dụ chi tiết về từng trường hợp sử dụng.
Leave a Reply