在SpringBoot環(huán)境中使用Mockito進(jìn)行單元測試的示例詳解
引言
Mockito是一個(gè)流行的Java mocking框架,它允許開發(fā)者以簡單直觀的方式創(chuàng)建和使用模擬對象(mocks)。Mockito特別適用于在Spring Boot環(huán)境中進(jìn)行單元測試,因?yàn)樗軌蜉p松模擬Spring應(yīng)用中的服務(wù)、存儲庫、客戶端和其他組件。通過使用Mockito,開發(fā)者可以模擬外部依賴,從而使單元測試更加獨(dú)立和可靠。這不僅有助于減少測試時(shí)對真實(shí)系統(tǒng)狀態(tài)的依賴,而且還允許開發(fā)者模擬各種場景,包括異常情況和邊緣情況。
示例 1: 模擬服務(wù)層中的方法
假設(shè)你有一個(gè)服務(wù) BookService,它依賴于一個(gè)DAO(數(shù)據(jù)訪問對象) 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層(控制器)
如果你想測試一個(gè)控制器,你可以使用Mockito來模擬服務(wù)層的方法,并使用 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客戶端進(jìn)行模擬
如果你的服務(wù)層使用了REST客戶端來調(diào)用外部API,你可以使用Mockito來模擬這些調(diào)用。
@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: 參數(shù)捕獲和驗(yàn)證
在某些情況下,你可能想要驗(yàn)證服務(wù)層調(diào)用了DAO的正確方法并且傳遞了正確的參數(shù)。Mockito的參數(shù)捕獲功能可以用于這種場景。
@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: 模擬靜態(tài)方法
從Mockito 3.4.0開始,你可以模擬靜態(tài)方法。這在測試使用了靜態(tài)工具方法的代碼時(shí)特別有用。
@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: 模擬連續(xù)調(diào)用
有時(shí)你需要模擬一個(gè)方法在連續(xù)調(diào)用時(shí)返回不同的值或拋出異常。
@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
在某些情況下,你可能不關(guān)心傳遞給mock方法的確切參數(shù)值。在這種情況下,可以使用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的方法
如果需要模擬一個(gè)返回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: 模擬泛型方法
當(dāng)需要模擬泛型方法時(shí),可以使用any()方法來表示任意類型的參數(shù)。
@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注解
有時(shí)你可能需要部分模擬一個(gè)對象。在這種情況下,可以使用@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
如果你需要驗(yàn)證mock對象上的方法調(diào)用順序,可以使用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();
}
}
總結(jié)
通過使用Mockito,可以模擬服務(wù)層、存儲庫、REST客戶端等組件,而無需依賴實(shí)際的實(shí)現(xiàn)。這樣不僅可以減少測試對外部系統(tǒng)的依賴,還可以模擬異常情況和邊緣用例,從而確保代碼在各種環(huán)境下的穩(wěn)健性。此外,Mockito的靈活性使得它可以輕松集成到現(xiàn)有的Spring Boot項(xiàng)目中,無論是對于簡單的單元測試還是更復(fù)雜的集成測試。總而言之,Mockito是Spring Boot開發(fā)者的強(qiáng)大工具,它可以提高測試的有效性和效率,從而幫助構(gòu)建更健壯、可靠的Spring應(yīng)用。
以上就是在SpringBoot環(huán)境中使用Mockito進(jìn)行單元測試的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Mockito單元測試的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
spring boot 監(jiān)聽容器啟動代碼實(shí)例
這篇文章主要介紹了spring boot 監(jiān)聽容器啟動代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
一次Jvm old過高的排查過程實(shí)戰(zhàn)記錄
這篇文章主要給大家介紹了一次Jvm old過高的排查過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
我從jdk1.8升級到j(luò)dk11所遇到的坑都有這些
這篇文章主要介紹了從jdk1.8升級到j(luò)dk11將會遇到的一些坑,本文給大家分享解決方案對大家的學(xué)習(xí)或工作具有參考借鑒價(jià)值,對jdk1.8升級到j(luò)dk11相關(guān)知識感興趣的朋友,快來看看吧2021-08-08
利用keytools為tomcat 7配置ssl雙向認(rèn)證的方法
雙向認(rèn)證和單向認(rèn)證原理基本差不多,只是除了客戶端需要認(rèn)證服務(wù)端以外,增加了服務(wù)端對客戶端的認(rèn)證,下面這篇文章主要介紹了利用keytools為tomcat 7配置ssl雙向認(rèn)證的方法,需要的朋友可以借鑒,下面來一起看看吧。2017-02-02
SpringBoot配置文件方式,在線yml文件轉(zhuǎn)properties
這篇文章主要介紹了SpringBoot配置文件方式,在線yml文件轉(zhuǎn)properties,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
關(guān)于泛型擦除問題的解決--Mybatis查詢類型轉(zhuǎn)換
這篇文章主要介紹了關(guān)于泛型擦除問題的解決--Mybatis查詢類型轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
Jackson處理Optional時(shí)遇到問題的解決與分析
Optional是Java實(shí)現(xiàn)函數(shù)式編程的強(qiáng)勁一步,并且?guī)椭诜妒街袑?shí)現(xiàn),但是Optional的意義顯然不止于此,下面這篇文章主要給大家介紹了關(guān)于Jackson處理Optional時(shí)遇到問題的解決與分析的相關(guān)資料,需要的朋友可以參考下2022-02-02

