Code Coverage With PowerMock on static method

PowerMock最強大的地方,就是可以幫我們mock static method,還可以幫我們mock private method、constructor,甚至Java System classes(link)。開發新功能無法避免使用到舊有的程式碼,而舊有的程式碼勢必有使用static method的utility class。本篇文章將分享如何撰寫測試,讓你可以正常的看到SUT(software under test)程式碼的coverage。

以下是本篇文章範例的類別圖:

SUT提供testMethod功能,會使用DOC(Depended-on Component)所提供的static method delegatedMethod。接下來我將使用PowerMockito去mock DOC static的行為:

@RunWith(PowerMockRunner.class)
@PrepareForTest({DOC.class})
public class SUTTest {
	@Test
	public void shouldReturnMockData_WhenDelegateExecutionToStaticMockDOC() {
		// Given
		String expectData = "MockData";
		mockStatic(DOC.class);
		doReturn(expectData).when(DOC.class);
		DOC.delegatedMethod();
 
		// When
		SUT sut = new SUT();
		String realData = sut.testMethod();
 
		// Then
		assertEquals(expectData, realData);
	}
}
接下來我們使用JUnit+code coverage tool去跑測試,以下為執行結果:

由此可見,mock “一般”的static method並不會造成coverage問題。但為什麼會有人對coverage問題抱持疑問呢? 答案是因為誤把SUT加到了@PrepareForTest之中:

@RunWith(PowerMockRunner.class)
@PrepareForTest({SUT.class, DOC.class})
public class SUTTest {
...

什麼時候會需要將SUT加入@PrepareForTest之中呢? 答案是如果你要Mock SUT裡面行為或者是Java System classes(如java.lang.*的class)的行為。

  1. Mock SUT裡面的行為代表你的SUT沒設計好,請重新想想你的設計。
  2. 面對Mock Java System classes的情況,如果你想要能夠正常看到coverage,不妨使用wrapper class去包裝使用到的物件。根據這篇文章,目前沒有一個很容易讓你使用powermock又可以正常使用coverage tool的方法,至少我還沒成功過。