Java中的單元測試私有方法
一、概述
在本文中,我們將簡要解釋為什麼直接測試私有方法通常不是一個好主意。然後,如果有必要,我們將演示如何在 Java 中測試私有方法。
2. 為什麼我們不應該測試私有方法
通常,我們編寫的單元測試應該只檢查我們的公共方法契約。私有方法是我們公共方法的調用者不知道的實現細節。此外,改變我們的實現細節不應該導致我們改變我們的測試。
一般來說,敦促測試私有方法會突出以下問題之一:
- 我們的私有方法中有死代碼。
- 我們的私有方法太複雜了,應該屬於另一個類。
- 我們的方法一開始並不意味著是私有的。
因此,當我們覺得需要測試私有方法時,我們真正應該做的是修復底層設計問題。
3. 一個例子:從私有方法中刪除死代碼
讓我們展示一個簡單的例子。
我們將編寫一個私有方法,該方法將返回Integer
的雙精度值。對於null
值,我們要返回null
:
private static Integer doubleInteger(Integer input) {
if (input == null) {
return null;
}
return 2 * input;
}
現在,讓我們編寫我們的公共方法。這將是課堂外的唯一入口點。
此方法接收一個Integer
作為輸入。它驗證這個Integer
不是null
,否則,它會拋出一個IllegalArgumentException
。之後,它調用私有方法返回兩倍的Integer
值:
public static Integer validateAndDouble(Integer input) {
if (input == null) {
throw new IllegalArgumentException("input should not be null");
}
return doubleInteger(input);
}
讓我們遵循我們的良好實踐並測試我們的公共方法契約。
首先,讓我們編寫一個測試,確保在輸入為null
時拋出IllegalArgumentException
:
@Test
void givenNull_WhenValidateAndDouble_ThenThrows() {
assertThrows(IllegalArgumentException.class, () -> validateAndDouble(null));
}
現在,讓我們檢查一個非空Integer
是否正確加倍:
@Test
void givenANonNullInteger_WhenValidateAndDouble_ThenDoublesIt() {
assertEquals(4, validateAndDouble(2));
}
讓我們看一下 JaCoCo 插件報告的覆蓋率:
正如我們所見,我們的私有方法中的空檢查沒有被我們的單元測試覆蓋。那我們應該測試一下嗎?
答案是不!重要的是要了解我們的私有方法並不存在於真空中。只有在我們的公共方法中驗證數據後才會調用它。因此,我們的私有方法中的 null 檢查永遠不會到達:它是死代碼,應該被刪除。
4. 如何在 Java 中測試私有方法
假設我們不氣餒測試我們的私有方法,讓我們解釋一下我們如何具體地做到這一點。
為了測試它,如果我們的私有方法有另一個可見性會很有幫助。好消息是我們可以用反射來模擬它。
我們的封裝類稱為Utils
。這個想法是訪問名為doubleInteger
的私有方法,該方法接受Integer
作為參數。然後我們將修改它的可見性,使其可以從Utils
類外部訪問。讓我們看看如何做到這一點:
private Method getDoubleIntegerMethod() throws NoSuchMethodException {
Method method = Utils.class.getDeclaredMethod("doubleInteger", Integer.class);
method.setAccessible(true);
return method;
}
現在,我們可以使用這種方法了。讓我們編寫一個測試,檢查給定一個null
對象,我們的私有方法返回null
。我們需要將該方法應用於將為null
的參數:
@Test
void givenNull_WhenDoubleInteger_ThenNull() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
assertEquals(null, getDoubleIntegerMethod().invoke(null, new Integer[] { null }));
}
讓我們再評論一下invoke
方法的用法。第一個參數是我們應用該方法的對象。由於doubleInteger
是靜態的,我們傳入了一個null
。第二個參數是一個參數數組。在這種情況下,我們只有一個參數,它是null
。
最後,讓我們演示一下如何測試非空輸入的情況:
@Test
void givenANonNullInteger_WhenDoubleInteger_ThenDoubleIt() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
assertEquals(74, getDoubleIntegerMethod().invoke(null, 37));
}
5. 結論
在本文中,我們描述了為什麼測試私有方法通常不是一個好主意。然後,我們展示瞭如何使用反射來測試 Java 中的私有方法。
與往常一樣,代碼可在 GitHub 上獲得。