日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
TestNG+PowerMock單元測試

單元測試(Unit Testing),是指對軟件或項目中最小可測試單元進行正確性檢驗的測試工作。單元是人為規(guī)定最小可測試的功能模塊,可以是一個模塊,一個函數(shù)或者一個類。單元測試需要與模塊開發(fā)進行隔離情況下進行測試。

成都創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站設(shè)計制作、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的平江網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

在程序開發(fā)完成后,我們往往不能保證程序 100% 的正確,通過單元測試的編寫,我們可以通過自動化的測試程序?qū)⑽覀兊妮斎胼敵龀绦蜻M行定義,通過斷言來 Check 各個 Case 的結(jié)果,檢測我們的程序。以提高程序的正確性,穩(wěn)定性,可靠性,節(jié)省程序開發(fā)時間。我們在項目中主要用到的單元測試框架有 Spring-Boot-Test TestNG、PowerMock 等。

TestNG,即 Testing, Next Generation,下一代測試技術(shù),是一套根據(jù) JUnit 和 NUnit 思想而構(gòu)建的利用注釋來強化測試功能的一個測試框架,即可以用來做單元測試,也可以用來做集成測試。

PowerMock 也是一個單元測試模擬框架,它是在其它單元測試模擬框架的基礎(chǔ)上做出的擴展。通過提供定制的類加載器以及一些字節(jié)碼篡改技巧的應(yīng)用,PowerMock 現(xiàn)了對靜態(tài)方法、構(gòu)造方法、私有方法以及 Final 方法的模擬支持,對靜態(tài)初始化過程的移除等強大的功能。

常用注解

1. TestNG 注解

  • @BeforeSuite 在該套件的所有測試都運行在注釋的方法之前,僅運行一次
  • @AftereSuite 在該套件的所有測試都運行在注釋方法之后,僅運行一次
  • @BeforeClass 在調(diào)用當(dāng)前類的第一個測試方法之前運行,注釋方法僅運行一次
  • @AftereClass 在調(diào)用當(dāng)前類的第一個測試方法之后運行,注釋方法僅運行一次
  • @BeforeMethod 注釋方法將在每個測試方法之前運行
  • @AfterMethod 注釋方法將在每個測試方法之后運行
  • @BeforeTest 注釋的方法將在屬于test標(biāo)簽內(nèi)的類的所有測試方法運行之前運行
  • @AfterTest 注釋的方法將在屬于test標(biāo)簽內(nèi)的類的所有測試方法運行之后運行
  • @DataProvider 標(biāo)記一種方法來提供測試方法的數(shù)據(jù)。注釋方法必須返回一個Object [] [],其中每個Object []可以被分配給測試方法的參數(shù)列表。要從該DataProvider接收數(shù)據(jù)的@Test方法需要使用與此注釋名稱相等的dataProvider名稱
  • @Parameters 描述如何將參數(shù)傳遞給@Test方法 ;適用于 xml 方式的參數(shù)化方式傳值
  • @Test 將類或方法標(biāo)記為測試的一部分,此標(biāo)記若放在類上,則該類所有公共方法都將被作為測試方法

2. PowerMock 注解

  • @Mock 注解實際上是 Mockito.mock() 方法的縮寫,我們只在測試類中使用它;
  • @InjectMocks 主動將已存在的 mock 對象注入到 bean 中, 按名稱注入, 但注入失敗不會拋出異常;
  • @Spy 封裝一個真實的對象,以便可以像其他 mock 的對象一樣追蹤、設(shè)置對象的行為;

示例代碼

1. 添加 pom.xml 依賴

以 Spring-Boot 項目為例,首先我們需要添加 TestNG + ProwerMock 依賴依賴如下:

 
 
 
 
  1.     org.springframework.boot
  2.     spring-boot-starter-test
  3.     test
  4.     org.testng
  5.     testng
  6.     ${testng.version}
  7.     test
  8.     org.powermock
  9.     powermock-api-mockito2
  10.     ${powermock.version}
  11.     test
  12.     org.powermock
  13.     powermock-module-junit4
  14.     ${powermock.version}
  15.     test
  16.     org.powermock
  17.     powermock-module-testng
  18.     ${powermock.version}
  19.     test

2. 增加單元測試

增加測試代碼

 
 
 
 
  1. import com.test.testng.dto.OrderDto;
  2. import com.test.testng.dto.UserDto;
  3. import org.mockito.*;
  4. import org.powermock.modules.testng.PowerMockTestCase;
  5. import org.testng.annotations.BeforeMethod;
  6. import org.testng.annotations.Test;
  7. import static org.junit.jupiter.api.Assertions.*;
  8. import static org.mockito.Mockito.when;
  9. public class OrderServiceTest extends PowerMockTestCase {
  10.     @BeforeMethod
  11.     public void before() {
  12.         MockitoAnnotations.openMocks(this);
  13.     }
  14.     @InjectMocks
  15.     private OrderService orderService;
  16.     @Mock
  17.     private UserService userService;
  18.     // 正常測試
  19.     @Test
  20.     public void testCreateOrder() {
  21.         //1. mock method start
  22.         UserDto userDto = new UserDto();
  23.         userDto.setId(100);
  24.         when(userService.get()).thenReturn(userDto);
  25.         //2. call business method
  26.         OrderDto order = orderService.createOrder(new OrderDto());
  27.         //3. assert
  28.         assertEquals(order.getId(), 100);
  29.     }
  30.     // 異常測試
  31.     @Test
  32.     public void testCreateOrderEx() {
  33.         //1. mock method start
  34.         when(userService.get()).thenThrow(new RuntimeException());
  35.         Exception exception = null;
  36.         try {
  37.             //2. call business method
  38.             orderService.createOrder(new OrderDto());
  39.         } catch (RuntimeException e) {
  40.             exception = e;
  41.         }
  42.         //3. assert
  43.         assertNotNull(exception);
  44.     }
  45. }

常用 Mock 方式

1. Mock 靜態(tài)方法

 
 
 
 
  1. //靜態(tài)方法
  2. UserDto dto = new UserDto();
  3. dto.setId(100000);
  4. PowerMockito.mockStatic(UserService.class);
  5. PowerMockito.when(UserService.loginStatic()).thenReturn(dto);
  6. UserDto userDto = UserService.loginStatic();
  7. assertEquals(100000, userDto.getId().intValue());

2. Mock 私有屬性

 
 
 
 
  1. //字段賦值
  2. ReflectionTestUtils.setField(orderService, "rateLimit", 99);

3. Mock 私有方法

 
 
 
 
  1. // 模擬私有方法
  2. MemberModifier.stub(MemberMatcher.method(UserService.class, "get1")).toReturn(new UserDto());
  3. // 測試私有方法
  4. Method method = PowerMockito.method(UserService.class, "get1", Integer.class);
  5. Object userDto = method.invoke(userService, 1);
  6. assertTrue(userDto instanceof UserDto);

進階使用

1. 參數(shù)化批量測試

在測試數(shù)據(jù)比較多的時候,我們可以通過 @DataProvider 生成數(shù)據(jù)源,通過 @Test(dataProvider = "xxx") 使用數(shù)據(jù), 如下所示:

 
 
 
 
  1. import com.test.testng.BaseTest;
  2. import com.test.testng.dto.UserDto;
  3. import org.mockito.InjectMocks;
  4. import org.testng.annotations.DataProvider;
  5. import org.testng.annotations.Test;
  6. import static org.testng.Assert.assertFalse;
  7. import static org.testng.AssertJUnit.assertTrue;
  8. public class UserServiceTest2 extends BaseTest {
  9.     @InjectMocks
  10.     private UserService userService;
  11.     // 定義數(shù)據(jù)源
  12.     @DataProvider(name = "test")
  13.     public static Object[][] userList() {
  14.         UserDto dto1 = new UserDto();
  15.         UserDto dto2 = new UserDto();
  16.         dto2.setSex(1);
  17.         UserDto dto3 = new UserDto();
  18.         dto3.setSex(1);
  19.         dto3.setFlag(1);
  20.         UserDto dto4 = new UserDto();
  21.         dto4.setSex(1);
  22.         dto4.setFlag(1);
  23.         dto4.setAge(1);
  24.         return new Object[][] {{dto1, null}, {dto2, null}, {dto3, null}, {dto4, null}};
  25.     }
  26.     // 正確場景
  27.     @Test
  28.     public void testCheckEffectiveUser() {
  29.         UserDto dto = new UserDto();
  30.         dto.setSex(1);
  31.         dto.setFlag(1);
  32.         dto.setAge(18);
  33.         boolean result = userService.checkEffectiveUser(dto);
  34.         assertTrue(result);
  35.     }
  36.     // 錯誤場景
  37.     @Test(dataProvider = "test")
  38.     public void testCheckEffectiveUser(UserDto dto, Object object) {
  39.         boolean result = userService.checkEffectiveUser(dto);
  40.         assertFalse(result);
  41.     }
  42. }

2. 復(fù)雜判斷保證測試覆蓋率

案例:

1.判斷有效用戶: 年齡大于 18 并且 sex = 1 并且 flag = 1

 
 
 
 
  1. public boolean checkEffectiveUser(UserDto dto) {
  2.     // 判斷有效用戶: 年齡大于 18 并且 sex = 1 并且 flag = 1
  3.     return Objects.equals(dto.getSex(), 1) &&
  4.         Objects.equals(dto.getFlag(), 1) &&
  5.         dto.getAge() != null && dto.getAge() >= 18;
  6. }

2.拆分邏輯。將其轉(zhuǎn)換為最簡單的 if ... else 語句。然后增加的單元測試,如下所示:

 
 
 
 
  1. public boolean checkEffectiveUser(UserDto dto) {
  2.     if (!Objects.equals(dto.getSex(), 1)) {
  3.         return false;
  4.     }
  5.     if (!Objects.equals(dto.getFlag(), 1)) {
  6.         return false;
  7.     }
  8.     if (dto.getAge() == null) {
  9.         return false;
  10.     }
  11.     if (dto.getAge() < 18) {
  12.         return false;
  13.     }
  14.     return true;
  15. }

3.拆分后我們可以看到,咱們只需要 5 條單元測試就能做到全覆蓋。

 
 
 
 
  1. public class UserServiceTest extends BaseTest {
  2.     @InjectMocks
  3.     private UserService userService;
  4.     // 覆蓋第一個 return 
  5.     @Test
  6.     public void testCheckEffectiveUser_0() {
  7.         UserDto dto =new UserDto();
  8.         boolean result = userService.checkEffectiveUser(dto);
  9.         assertFalse(result);
  10.     }
  11.     // 覆蓋第二個 return 
  12.     @Test
  13.     public void testCheckEffectiveUser_1() {
  14.         UserDto dto =new UserDto();
  15.         dto.setSex(1);
  16.         boolean result = userService.checkEffectiveUser(dto);
  17.         assertFalse(result);
  18.     }
  19.     // 覆蓋第三個 return 
  20.     @Test
  21.     public void testCheckEffectiveUser_2() {
  22.         UserDto dto =new UserDto();
  23.         dto.setSex(1);
  24.         dto.setFlag(1);
  25.         boolean result = userService.checkEffectiveUser(dto);
  26.         assertFalse(result);
  27.     }
  28.     // 覆蓋第四個 return
  29.     @Test
  30.     public void testCheckEffectiveUser_3() {
  31.         UserDto dto =new UserDto();
  32.         dto.setSex(1);
  33.         dto.setFlag(1);
  34.         dto.setAge(1);
  35.         boolean result = userService.checkEffectiveUser(dto);
  36.         assertFalse(result);
  37.     }
  38.     // 覆蓋第五個 return
  39.     @Test
  40.     public void testCheckEffectiveUser_4() {
  41.         UserDto dto =new UserDto();
  42.         dto.setSex(1);
  43.         dto.setFlag(1);
  44.         dto.setAge(18);
  45.         boolean result = userService.checkEffectiveUser(dto);
  46.         assertTrue(result);
  47.     }
  48. }

4.單測覆蓋率檢測檢測

3. 通過斷言校驗方法參數(shù)

1.assert:斷言是 java 的一個保留字,用來對程序進行調(diào)試,后接邏輯運算表達式,如下:

 
 
 
 
  1. int a = 0, b = 1;
  2. assert a == 0 && b == 0;
  3. // 使用方法:javac編譯源文件,再 java -ea class文件名即可。

2.在 Spring-Boot 中可以使用 Spring 提供的 Assert 類的方法對前端來的參數(shù)進行校驗,如:

 
 
 
 
  1. // 檢查年齡 >= 18 歲
  2. public boolean checkUserAge(UserDto dto){
  3.     Assert.notNull(dto.getAge(), "用戶年齡不能為空");
  4.     Assert.isTrue(dto.getAge() >= 18, "用戶年齡不能小于 18 歲");
  5.     return Boolean.TRUE;
  6. }

3.如果是需要轉(zhuǎn)換為,rest api 返回的統(tǒng)一相應(yīng)消息,我們可以通過:

 
 
 
 
  1. @ControllerAdvice
  2. public class GlobalExceptionHandler {
  3.     @ResponseBody
  4.     @ExceptionHandler(value = IllegalArgumentException.class)
  5.     public Response handleArgError(IllegalArgumentException e){
  6.         return new Response().failure().message(e.getMessage());
  7.     }
  8. }

總結(jié)

原則上來講,在功能模塊的設(shè)計過程中我們應(yīng)該遵循一下原則(參考 《軟件工程-結(jié)構(gòu)化設(shè)計準(zhǔn)則》):

  1. 模塊大小適中
  2. 合適的系統(tǒng)調(diào)用深度
  3. 多扇入、少扇出(增加復(fù)用度, 減少依賴程度)
  4. 單入口,單出口
  5. 模塊的作用域,應(yīng)該在模塊內(nèi)
  6. 功能應(yīng)該可以預(yù)測的
  7. 高內(nèi)聚,低耦合
  8. 系統(tǒng)分解有層次
  9. 較少的數(shù)據(jù)冗余

參考文檔

https://testng.org/doc/

https://github.com/powermock/powermock

https://www.netconcepts.cn/detail-41004.html


標(biāo)題名稱:TestNG+PowerMock單元測試
轉(zhuǎn)載來源:http://m.5511xx.com/article/dhggppd.html