單元測試(一):快速瞭解單元測試

Why

單元測試幫我們快速驗證代碼流程(超快速得到代碼結果),更早了解程序的問題(發現代碼bug如隱藏的空指針等),讓我們能瞭解需求(測試用例覆蓋所有邏輯鏈路),利於提高代碼能力。

What

常用單元測試框以及常用用法

junit

  • 常用註解
    @RunWith:制定測試運行容器
    @BeforeClass(測試類啓動時執行一次)
    @AfterClass(測試類銷燬時執行一次)
    @Test 方法註解,測試用例
    @Before 方法註解,測試方法執行前執行,常用作配置或創建對象
    @After 方法註解,測試方法執行後執行,常用於資源清理關閉等
    @IgnoreTest 忽略測試用例
    @Rule 不影響原有case的代碼,減少了特有操作和test case原邏輯的耦合
  • Assertions斷言:(或者可使用AssertJ斷言庫有更多斷言方法)
    assertEquals:比較值
    assertArrayEquals:比較數組或list的值是否相同
    assertTrue/AssertFalse:判斷條件真假()
    assertNull/assertNotNull:驗證對象是否爲空或不爲空
    assertSame/assertNotNull:判斷是否同一引用(==)
    fail:強制不通過
    assertThat(actual, matcher):按照匹配符規則驗證
    matcher匹配符
    • 一般對象匹配符:
      allOf:所有條件都成立才通過,相當於&&
      eg:assertThat(testNumb,allOf(greaterThan(8),lessThan(16));
      anyOf:所有條件只要有一個成立,相當於||
      anything:無論什麼條件,永遠爲true
      is:待測的object等於後面給出的object
      not:前面待測的object不等於後面給出的object
    • 字符串匹配符:
      containsString:待測字符串包含 子字符串
      endsWith/startsWith:待測字符串以子字串結尾/開頭
      equalTo:測試數值之間,字符串 之間和對加粗樣式象之間是否相等
      equalToIgnoringCase:在忽略大小寫的情況下等於
      equalToIgnoringWhiteSpace:忽略頭尾的任意個空格的情況下等於
    • 數值匹配符:
      closeTo:浮點型數testedDouble在某範圍之內
      eg: assertThat(testedDouble, closeTo(20.0,0.5 ));
      greaterThan/lessThan:大於/小於
      greaterThanOrEqualTo/lessThanOrEqualTo:大於等於/小於等於
    • collection相關匹配符:
      hasEntry: Map對象含有一個鍵值爲"key"對應元素值爲"value"的Entry項
      hasItem:測試的迭代對象iterableObject含有元素“element”項
      hasKey:Map對象mapObject含有鍵值“key”
      hasValue:Map對象mapObject含有元素值“value”

Mockito

對象mock框架,創建虛擬對象隔離測試依賴,用於給不易構造的對象創建虛擬對象來測試

  • 常用註解
    @Mock:定義的mock對象將會被注入到這個待測試的對象中(默認不執行,默認返回null)
    @InjectMock:聲明瞭一個待測試的對象()
    @Spy:監視真實的對象
    @Captor

  • 常用方法
    when(mockObj).thenReturn(輸出指定值或對象)😕/有返回值的方法
    when(moc對象).notify();//模擬無返回值的方法
    doThrow(new XXXException()).when(mocObject).callSomeMethod();//模擬拋出異常
    verify(mock對象方法,timess(N))//跟蹤所有方法的調用和參數調用情況,驗證行爲是否發生
    mock(mockObj,RETURNS_SMART_NULLS);//創建mock對象的可選空參數,避免普通調用時拋出空指針異常
    when().thenAnswer(new MyAnswer());//自定義預期返回值
    doCallRealMeth().when(mockA).goHome(); //mock對象調用部分真實的方法
    ArgumentCaptor驗證傳入方法的參數
    ArgumentCaptor.forClass(XXX.class)//構建參數對象
    argument.capture();//捕獲參數
    argument.getValue();//回去方法參數的值
    argument.getAllValues();//獲取多次調用後的參數值

  • 斷言
    Matchers:類似Junit斷言,比Junit斷言有更多的斷言方法

    • 數據類型斷言類:
      any()/anyInt()/anyString()…
    • 集合斷言類:
      anyList/anyListOf/anyMap/anyMapOf/anySet/anySetOf/anyCollection/anyCollectionOf
    • 對象斷言:
      equal(x)/same(T)/isNull()/notNull()/isNotNull()
    • 字符串:
      contains(String s)/matches(regex)/endsWith/startsWith/
    • 參數:
      argThat(Matcher)/charThat/intThat…;自定義參數匹配
    • 執行順序:
      InOrder:驗證執行順序 eg:inOrder(Obj1,Obj2,Obj3);//必須是按照定義好的順序執行否之不通過驗證
    • 調用:
      verifyZeroInteractions(obj1,obj2);//驗證對象零互動
      verifyNoMoreInteractions(obj);//驗證對象是否有未被驗證的互動性爲,有互動行爲通過,有位被驗證的行爲不通過

    常見使用場景

PowerMock

可以實現完成對private/static/final方法的Mock(模擬)

  • 常用註解
    @RunWith(PowerMockRunner.class); //使用PowerMockRunner進行測試非public方法是必須使用此類
    @PrepareForTest({MockUtil.class}); //所有需要測試的類列在此處,適用於模擬final類或有final, private, static, native方法的類
    @PowerMockIgnore(“javax.management.*”) ;//爲了解決使用powermock後,提示classloader錯誤

  • 常用場景
    (1)驗證普通方法public
    同Mock
    (2)驗證靜態方法static
    PowerMockito.mockStatic(XXX.class);
    PowerMockito.when(XXX.callStaticMethod([xxx])).thenReturn(x);
    Assert…;
    (3)驗證私有方法的調用
    Whitebox.invokeMethod(xxx,“privateFunc”,arg1,arg2…argn);//獲取私有方法的返回值
    (4)驗證方法內new出來的對象(即private對象)
    NewObj newObj = PowerMockito.mock(NewObj.class);
    PowerMockito.whenNew(NewObj.class).withArguments(T)/.withNoArguments().thenReturn(newObj)
    PowerMockito.when(XXX.callSomeMehod([xxx])).thenReturn(X);
    Assert…;
    (5)驗證私有方法private被調用的方法
    @Spy
    private XXX xxx;//驗證private方法必須模擬一個真實存在的測試對象
    PowerMockito.when(xxx,“privateFunc”).thenReturn(“xxxx”);//模擬私有方法的返回值
    PowerMockito.verifyPrivate(xxx, Mockito.times(1));//驗證私有方法被調用
    (6)驗證final方法(類似驗證靜態方法)
    PowerMockito.mockStatic(XXX.class);
    PowerMockito.when(XXX.callStaticMethod([xxx])).thenReturn(x);
    Assert…;
    (7)驗證單例模式的對象
    Whitebox.setInternalState(Singleton.class, “INSTANCE”, singleton);
    PowerMockito.when(singleton.max(Mockito.anyInt(), Mockito.anyInt())).then(returnsFirstArg());
    Assert…
    採坑記錄

實操採坑不間斷更新記錄

(1)RestTemplate:預定義的返回值無法傳遞

:直接使用@Mock或者Mockito.mock()方法mock的rest Template對象注入到service層後,再使用Mockito.when(restTemplate.xxx).thenReturn(xxxResponseEntity)驗證預定義的返回值時,返回值無法傳遞到service層,單測走到service層後取返回值會null
填坑:使用SpringBoot的測試註解,將測試環境模擬再SpringBoot容器內,將restTemplate注和serviceImpl都構建再容器內進行測試:

@RunWith(SpringRunner.class@SpringTest
	@MockBean
	private RestTemplate restTemplate;
	@Autowired
	private XXXServiceImpl xxxServiceImpl;
	...
	@Test
	public void testXX(){
		...
		String myRespJsonStr = this.mockXXXJson();//構建返回Json字符串
		Mockito
					.when(restTtemplate.postForEntity(anyString(),any(XXXReeust.class),Mockito.eq(String.class)))
					.thenReturn(new Response<>(myRespJsonStr ,HttpStatus.OK));
		...
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章