# springboot3-mockito **Repository Path**: githubGejin/springboot3-mockito ## Basic Information - **Project Name**: springboot3-mockito - **Description**: springboot mock - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-03-12 - **Last Updated**: 2025-03-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Getting Started ### Reference Documentation For further reference, please consider the following sections: * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/3.4.3/maven-plugin) * [Create an OCI image](https://docs.spring.io/spring-boot/3.4.3/maven-plugin/build-image.html) ### Maven Parent overrides Due to Maven's design, elements are inherited from the parent POM to the project POM. While most of the inheritance is fine, it also inherits unwanted elements like `` and `` from the parent. To prevent this, the project POM contains empty overrides for these elements. If you manually switch to a different parent and actually want the inheritance, you need to remove those overrides. ## Springboot3, Mockito, JUnit5示例 学习使用[JUnit 5](https://howtodoinjava.com/junit-5-tutorial/)和[Mockito](https://howtodoinjava.com/mockito/junit-mockito-example/)测试框架为 Spring Boot 应用程序的服务层编写[单元测试](https://howtodoinjava.com/best-practices/unit-testing-best-practices-junit-reference-guide/)。我们在此演示中使用[Spring Boot 3。](https://howtodoinjava.com/java/whats-new-spring-6-spring-boot-3/)对于 Spring Boot 应用程序,我们只需要更改 import 语句,一切都会自动运行。 ```java @ExtendWith(MockitoExtension.class) public class ItemServiceTest { @Mock private ItemRepository itemRepository; @InjectMocks private ItemService itemService; // 假设 ItemService 使用 ItemRepository @Test public void testCreateItem() { // ... } } ``` ## 1. Maven *spring-boot-starter-test*依赖项会间接导入 JUnit 5 和 Mockito。因此我们只需要包含此依赖项。 ```xml org.springframework.boot spring-boot-starter-test test ``` ##  2. 初始化模拟 在这个例子中,我们主要对两个类`EmployeeManager`和`EmployeeDao`进行单元测试。顾名思义,manager 类代表服务层,而 dao 类与数据库交互。 `EmployeeManager`类依赖于`EmployeeDao`来从数据库获取数据,这些数据最终返回给控制器类。为了测试`EmployeeManager`中的方法,我们可以通过以下两种方式创建一个 JUnit 测试类*TestEmployeeManager* : ### 2.1. @Mock 与 @InjectMocks **@Mock** 注解为所注解的类创建一个模拟实现。 **@InjectMocks**还创建注解类型的模拟实现并将依赖的模拟注入其中。 在上面的例子中,我们用`@InjectMocks`注解了`EmployeeManager`类,因此 mockito 将为`EmployeeManager`类创建模拟对象,并将`EmployeeDao`的模拟依赖项注入其中。 ### 2.2. 使用 MockitoExtension 进行初始化 要使用 JUnit 处理 Mockito 注释,我们需要使用*MockitoExtention* ,它会自动初始化所有带有[`@Mock`和`@InjectMocks`注释的](https://howtodoinjava.com/mockito/mockito-annotations/)对象。 ```java @ExtendWith(MockitoExtension.class) public class TestEmployeeManager { @InjectMocks EmployeeManager manager; @Mock EmployeeDao dao; //tests } ``` ### 2.3. 使用 MockitoAnnotations.openMocks() 进行初始化 如果我们不使用*MockitoJUnitRunner*类方法,那么我们可以使用*静态*方法 `MockitoAnnotations.openMocks()` 。在初始化 junit 测试时,此方法还会初始化模拟对象。 ```java public class ServiceTests { @InjectMocks EmployeeService service; @Mock EmployeeRepository dao; @BeforeEach public void init() { MockitoAnnotations.openMocks(this); } //tests } ``` ##   3. Sprig 启动测试 让我们看几个编写 junit 测试的例子,使用 mockito 创建的模拟对象对*服务层和[DAO 层](https://howtodoinjava.com/best-practices/how-you-should-unit-test-dao-layer/)方法进行单元测试*。 一些示例方法可以是*getAllEmployees()*返回`EmployeeVO`对象列表、 `getEmployeeById(int id)`根据给定的 id 返回员工;以及`createEmployee()`添加员工对象并返回`void` 。 ### 3.1. 单元测试示例 以下类包含服务类方法的测试。它使用*Mockito.when()*方法创建测试存根。 ```java import com.mock.mockito.dao.EmployeeRepository; import com.mock.mockito.entity.Employee; 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; import java.util.ArrayList; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class EmployeeServiceTest { @InjectMocks EmployeeService service; @Mock EmployeeRepository repository; /** * 保存对象的方法 */ @Test public void testSave(){ Employee employee = new Employee("1", "2"); Employee save = service.save(employee); assertEquals(save, null); } /** * 测试异常情况 */ @Test public void testSaveNull(){ when(service.save(null)).thenThrow(new NullPointerException()); } /** * 查询所有的数据 * * @return list */ @Test public void testFindAllEmployees(){ // 模拟从dao 层查询出所有数据 List list = initEmployees(); when(repository.findAll()).thenReturn(list); // 调用service 层中的findAll() 方法查询数据 List all = service.findAll(); // 判断两次查询的数据数量是否一致 assertEquals(list.size(), all.size()); } /** * 初始化数据 * * @return list */ private List initEmployees() { List list = new ArrayList<>(); Employee empOne = new Employee("John", "John"); Employee empTwo = new Employee("Alex", "kolenchiski"); Employee empThree = new Employee("Steve", "Waugh"); list.add(empOne); list.add(empTwo); list.add(empThree); return list; } } ``` 请注意,**如果在测试执行期间未调用初始化的模拟,则*Mockito*会抛出*UnsupportedStubbingException*** 。如果有此类可选的模拟行为,则使用**Mockito.lenient()** 如下所示: > **Mockito**.**lenient**(**)**.**when**(dao **.**isEmployeeDeleted**(**)**)**.**thenReturn**(**Boolean**.**False**)**;** ### 3.2. 需要模拟的服务类 ```java package com.mock.mockito.service; import com.mock.mockito.dao.EmployeeRepository; import com.mock.mockito.entity.Employee; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class EmployeeService { @Autowired EmployeeRepository employeeRepository; public Employee save(Employee employee) { //... if (employee != null){ Employee save = employeeRepository.save(employee); return save; }else { throw new NullPointerException("the employee is not allowed be null"); } } public List findAll() { //... List all = (List) employeeRepository.findAll(); return all; } public void deleteById(Integer id) { //... if (id != null){ employeeRepository.deleteById(id); }else { throw new NullPointerException("the id is not allowed be null"); } } public void deleteAll() { //... employeeRepository.deleteAll(); } } ``` **实体类:** ```java package com.mock.mockito.entity; public class Employee { private String firstName; private String lastName; public Employee(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } } ``` **dao层:** ```java package com.mock.mockito.dao; import com.mock.mockito.entity.Employee; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface EmployeeRepository extends CrudRepository { } ``` ## 4. 结论 本 mockito 教程教我们使用 JUnit 和 Mockito 对 spring boot 应用程序中的服务层进行单元测试。我们学习了如何设置测试类和编写 JUnit 测试。我们还学习了*@Mock*和*@InjectMocks*注释之间的区别。