背景
基于 springboot 微服務(wù)架構(gòu)給單元測試帶來的問題:
- springboot 單元測試啟動家長過程非常緩慢,后期服務(wù)啟動達到分鐘級,非常影響效率
- 服務(wù)之間相互依賴非常嚴重,單元測試的運行非常依賴其它服務(wù)穩(wěn)定性
- 第三方服務(wù)和中間件,測試過程產(chǎn)生大量垃圾數(shù)據(jù),污染環(huán)境,非常笨重,甚至產(chǎn)生資損。
解決辦法
采用 EasyMock, PowerMock,Mockito 等mock 框架, 屏蔽外部依賴,還原單元測試本身。
Mockito使用
由于spring-boot-starter-test 默認集成了 Mockito的依賴,本文優(yōu)先介紹 Mockito框架的使用。
依賴
一般不需要手動指定
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.3.3</version>
</dependency>
導(dǎo)入
導(dǎo)入常用靜態(tài)方法
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
模擬對象
Mock 對象的創(chuàng)建
語法: mock(class or interface)
用例:
OrderService orderService = mock(OrderService.class);
設(shè)置預(yù)期返回值
語法: when(mock.someMethod()).thenReturn(value)
用例:
when(productService.getById(1L)).thenReturn(new Product(1L,"mate50", new BigDecimal("9000")));
驗證被測試類方法
語法: verify(mock).someMethod(…),verify(mock,times(integer)).someMethod(…)
用例:
verify(orderMapper).insert(any(Order.class));
verify(stockService, times(2)).deduct(anyLong(), eq(1));
配合注解使用
語法: @Mock, mock 一個對象
語法: @InjectMocks , 依賴注入 mock對象
用例:
/**
* orderMapper, stockService等為 OrderServiceImpl的依賴對象.
*/
@InjectMocks
private OrderService orderService = new OrderServiceImpl();
@Mock
private OrderMapper orderMapper;
@Mock
private StockService stockService;
@Mock
private AmountService amountService;
@Mock
private ProductService productService;
完整案列
@Test
public void testSubmitOrder() {
Long userId = 1L;
List<Product> productList = Lists.newArrayList(
new Product(1L, 1),
new Product(2L, 1)
);
// 模擬productService.getById方法,返回一個Product對象
when(productService.getById(1L)).thenReturn(new Product(1L,"mate50", new BigDecimal("9000")));
when(productService.getById(2L)).thenReturn(new Product(2L,"充電寶", new BigDecimal("120")));
boolean result = orderService.submitOrder(userId, productList);
// submitOrder 驗證返回結(jié)果為true
assertTrue(result);
// 驗證stockService.deduct方法被調(diào)用了2次
verify(stockService, times(2)).deduct(anyLong(), eq(1));
// 驗證orderMapper.insert方法被調(diào)用了1次
verify(orderMapper, times(1)).insert(any(Order.class));
}
使用codeGPT 生成單元測試
prompt: Write JUnit Tests for the following code by using java, use mockito, use Chinese comment:
完整代碼
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class OrderServiceTest {
@Mock
private ProductService productService;
@Mock
private StockService stockService;
@Mock
private OrderMapper orderMapper;
@InjectMocks
private OrderService orderService;
@Test
public void testSubmitOrder() {
// given
List<Product> products = Arrays.asList(
new Product(1L, "product1", BigDecimal.valueOf(10), 2),
new Product(2L, "product2", BigDecimal.valueOf(20), 1)
);
when(productService.getById(1L)).thenReturn(new Product(1L, "product1", BigDecimal.valueOf(10), 10));
when(productService.getById(2L)).thenReturn(new Product(2L, "product2", BigDecimal.valueOf(20), 10));
// when
boolean result = orderService.submitOrder(123L, products);
// then
assertEquals(true, result);
verify(productService, times(2)).getById(anyLong());
verify(stockService, times(3)).deduct(anyLong(), anyInt());
verify(orderMapper).insert(any(Order.class));
}
}
結(jié)論:通過觀察,gpt 生成的單元測試跟手動寫的單元測試非常相近,幾乎直接可以使用。文章來源:http://www.zghlxwxcb.cn/news/detail-700646.html
一點心得
不要去糾結(jié)GPT 哪方面做的不好,要多思考,利用GPT能為我們做什么。文章來源地址http://www.zghlxwxcb.cn/news/detail-700646.html
到了這里,關(guān)于單元測試編寫最佳實踐(ChatGPT+Mockito+JUnit)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!