Mockito是一个流行的Java mocking框架,它允许开发者以简单直观的方式创建和使用模拟对象(mocks)。Mockito特别适用于在Spring Boot环境中进行单元测试,因为它能够轻松模拟Spring应用中的服务、存储库、客户端和其他组件。通过使用Mockito,开发者可以模拟外部依赖,从而使单元测试更加独立和可靠。这不仅有助于减少测试时对真实系统状态的依赖,而且还允许开发者模拟各种场景,包括异常情况和边缘情况。

示例 1: 模拟服务层中的方法

假设你有一个服务 BookService,它依赖于一个DAO(数据访问对象) BookRepository。你可以使用Mockito来模拟 BookRepository 的行为。


@SpringBootTest


public class BookServiceTest {



@Mock


private BookRepository bookRepository;



@InjectMocks


private BookService bookService;



@BeforeEach


public void setup() {


MockitoAnnotations.openMocks(this);


}



@Test


public void testFindBookById() {


Book mockBook = new Book(1L, "Mockito in Action", "John Doe");


when(bookRepository.findById(1L)).thenReturn(Optional.of(mockBook));



Book result = bookService.findBookById(1L);



assertEquals("Mockito in Action", result.getTitle());


}


}
示例 2: 模拟Web层(控制器)

如果你想测试一个控制器,你可以使用Mockito来模拟服务层的方法,并使用 MockMvc 来模拟HTTP请求。


@WebMvcTest(BookController.class)


public class BookControllerTest {



@MockBean


private BookService bookService;



@Autowired


private MockMvc mockMvc;



@Test


public void testGetBook() throws Exception {


Book mockBook = new Book(1L, "Mockito for Beginners", "Jane Doe");


when(bookService.findBookById(1L)).thenReturn(mockBook);



mockMvc.perform(get("/books/1"))


.andExpect(status().isOk())


.andExpect(jsonPath("$.title").value("Mockito for Beginners"));


}


}
示例 3: 模拟异常情况

你还可以使用Mockito来测试异常情况。


@SpringBootTest


public class BookServiceTest {



@Mock


private BookRepository bookRepository;



@InjectMocks


private BookService bookService;



@Test


public void testBookNotFound() {


when(bookRepository.findById(1L)).thenReturn(Optional.empty());



assertThrows(BookNotFoundException.class, () -> {


bookService.findBookById(1L);


});


}


}
示例 4: 使用Mockito对REST客户端进行模拟

如果你的服务层使用了REST客户端来调用外部API,你可以使用Mockito来模拟这些调用。


@SpringBootTest


public class ExternalServiceTest {



@Mock


private RestTemplate restTemplate;



@InjectMocks


private ExternalService externalService;



@Test


public void testGetExternalData() {


String response = "{\"key\":\"value\"}";


when(restTemplate.getForObject("http://external-api.com/data", String.class))


.thenReturn(response);



String result = externalService.getExternalData();



assertEquals("{\"key\":\"value\"}", result);


}


}
示例 5: 参数捕获和验证

在某些情况下,你可能想要验证服务层调用了DAO的正确方法并且传递了正确的参数。Mockito的参数捕获功能可以用于这种场景。


@SpringBootTest


public class UserServiceTest {



@Mock


private UserRepository userRepository;



@InjectMocks


private UserService userService;



@Test


public void testCreateUser() {


User user = new User("JohnDoe", "john@doe.com");



userService.createUser(user);



ArgumentCaptor<User> userArgumentCaptor = ArgumentCaptor.forClass(User.class);


verify(userRepository).save(userArgumentCaptor.capture());


User capturedUser = userArgumentCaptor.getValue();



assertEquals("JohnDoe", capturedUser.getUsername());


}


}
示例 6: 模拟静态方法

从Mockito 3.4.0开始,你可以模拟静态方法。这在测试使用了静态工具方法的代码时特别有用。


@SpringBootTest


public class UtilityServiceTest {



@Test


public void testStaticMethod() {


try (MockedStatic<UtilityClass> mockedStatic = Mockito.mockStatic(UtilityClass.class)) {


mockedStatic.when(() -> UtilityClass.staticMethod("input")).thenReturn("mocked output");



String result = UtilityService.callStaticMethod("input");



assertEquals("mocked output", result);


}


}


}
示例 7: 模拟连续调用

有时你需要模拟一个方法在连续调用时返回不同的值或抛出异常。


@SpringBootTest


public class ProductServiceTest {



@Mock


private ProductRepository productRepository;



@InjectMocks


private ProductService productService;



@Test


public void testProductAvailability() {


when(productRepository.checkAvailability(anyInt()))


.thenReturn(true)


.thenReturn(false);



assertTrue(productService.isProductAvailable(123));


assertFalse(productService.isProductAvailable(123));


}


}
示例 8: 使用ArgumentMatchers

在某些情况下,你可能不关心传递给mock方法的确切参数值。在这种情况下,可以使用Mockito的ArgumentMatchers


@SpringBootTest


public class NotificationServiceTest {



@Mock


private EmailClient emailClient;



@InjectMocks


private NotificationService notificationService;



@Test


public void testSendEmail() {


notificationService.sendEmail("hello@example.com", "Hello");



verify(emailClient).sendEmail(anyString(), eq("Hello"));


}


}
示例 9: 模拟返回void的方法

如果需要模拟一个返回void的方法,可以使用doNothing()doThrow()等。


@SpringBootTest


public class AuditServiceTest {



@Mock


private AuditLogger auditLogger;



@InjectMocks


private UserService userService;



@Test


public void testUserCreationWithAudit() {


doNothing().when(auditLogger).log(anyString());



userService.createUser(new User("JaneDoe", "jane@doe.com"));



verify(auditLogger).log(contains("User created:"));


}


}
示例 10: 模拟泛型方法

当需要模拟泛型方法时,可以使用any()方法来表示任意类型的参数。


@SpringBootTest


public class CacheServiceTest {



@Mock


private CacheManager cacheManager;



@InjectMocks


private ProductService productService;



@Test


public void testCaching() {


Product mockProduct = new Product("P123", "Mock Product");



when(cacheManager.getFromCache(any(), any())).thenReturn(mockProduct);



Product result = productService.getProduct("P123");



assertEquals("Mock Product", result.getName());


}


}
示例 11: 使用@Spy注解

有时你可能需要部分模拟一个对象。在这种情况下,可以使用@Spy注解。


@SpringBootTest


public class OrderServiceTest {



@Spy


private OrderProcessor orderProcessor;



@InjectMocks


private OrderService orderService;



@Test


public void testOrderProcessing() {


Order order = new Order("O123", 100.0);


doReturn(true).when(orderProcessor).validateOrder(order);



boolean result = orderService.processOrder(order);



assertTrue(result);


}


}
示例 12: 使用InOrder

如果你需要验证mock对象上的方法调用顺序,可以使用InOrder


@SpringBootTest


public class TransactionServiceTest {



@Mock


private Database database;



@InjectMocks


private TransactionService transactionService;



@Test


public void testTransactionOrder() {


transactionService.performTransaction();



InOrder inOrder = inOrder(database);


inOrder.verify(database).beginTransaction();


inOrder.verify(database).commitTransaction();


}


}
总结

通过使用Mockito,可以模拟服务层、存储库、REST客户端等组件,而无需依赖实际的实现。这样不仅可以减少测试对外部系统的依赖,还可以模拟异常情况和边缘用例,从而确保代码在各种环境下的稳健性。此外,Mockito的灵活性使得它可以轻松集成到现有的Spring Boot项目中,无论是对于简单的单元测试还是更复杂的集成测试。总而言之,Mockito是Spring Boot开发者的强大工具,它可以提高测试的有效性和效率,从而帮助构建更健壮、可靠的Spring应用

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】

​​​软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

在这里插入图片描述

更多推荐