如果一個類,包含了一些靜態方法,以確保沒有人錯誤地初始化這個類的一個實例,我做了一個私人的構造函數:如何在Java應用程序中測試私有構造函數?
private Utils() {
}
現在..怎麼會這樣進行測試,鑑於構造函數不能被看到?這可以根據測試覆蓋嗎?
如果一個類,包含了一些靜態方法,以確保沒有人錯誤地初始化這個類的一個實例,我做了一個私人的構造函數:如何在Java應用程序中測試私有構造函數?
private Utils() {
}
現在..怎麼會這樣進行測試,鑑於構造函數不能被看到?這可以根據測試覆蓋嗎?
使用反射,你可以調用私有構造:
Constructor<Util> c = Utils.class.getDeclaredConstructor();
c.setAccessible(true);
Utils u = c.newInstance(); // Hello sailor
但是,你甚至可以使這不可能的:
private Utils() {
throw new UnsupportedOperationException();
}
通過構造函數中拋出異常,你會阻止所有的嘗試。
我會讓類本身final
過,只是「因爲」:
public final class Utils {
private Utils() {
throw new UnsupportedOperationException();
}
}
+1。關於例外的優秀點! – JAM
不錯。另外,如果添加了異常,實際上也可能有爲此進行單元測試的原因。 – msandiford
我發現UnsupportedOperationException比IllegalStateException更合適。 –
@Test
public//
void privateConstructorTest() throws Exception {
final Constructor<?>[] constructors = Utils.class.getDeclaredConstructors();
// check that all constructors are 'private':
for (final Constructor<?> constructor : constructors) {
Assert.assertTrue(Modifier.isPrivate(constructor.getModifiers()));
}
// call the private constructor:
constructors[0].setAccessible(true);
constructors[0].newInstance((Object[]) null);
}
測試代碼的意圖..總是:)
例如:如果該點構造函數是不可見的,那麼你需要測試的是這個事實,沒有別的。
使用反射API查詢構造函數並驗證它們是否具有私有屬性集。
我會做這樣的事情:
@Test()
public void testPrivateConstructors() {
final Constructor<?>[] constructors = Utils.class.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
assertTrue(Modifier.isPrivate(constructor.getModifiers()));
}
}
如果你想擁有的對象構造一個適當的測試,你應該測試的公共API,它可以讓你獲得的構造的對象。這就是所說的API應該存在的原因:正確構建對象,所以你應該測試它:)。
好主意。代碼覆蓋率太差的工具不知道你測試過它。 –
請參閱https://github.com/trajano/commons-testing以瞭解執行此操作的庫以及更多用於測試實用程序類的庫。 –
如果您有一個私有構造函數,它會從您的代碼的某種非私有方法調用。所以你測試了這個方法,並且你的構造函數被覆蓋了。按照每種方法進行測試沒有宗教美德。您正在尋找函數或更好的分支覆蓋級別,只需通過使用它的代碼路徑來執行構造函數即可獲得。
如果該代碼路徑錯綜複雜且難以測試,則可能需要重構它。
,以確保沒有一個錯誤初始化此類
通常我做什麼,是對方法/構造從私有更改爲默認包可見的一個實例。我爲測試類使用相同的包,所以從測試中可以訪問方法/構造函數,即使它不是來自外部。
要執行政策,不能實例化類,你可以:
或者同時應用1 + 2,如果您的測試與目標類共享相同的包,則仍然可以繼承並運行構造函數。 這應該是相當「錯誤證明」;惡意程序員總是會找到一個解決辦法:)
如果您在構造函數中添加例外,如:
private Utils() {
throw new UnsupportedOperationException();
}
的constructor.newInstance()
在測試類的調用將拋出一個InvocationTargetException
,而不是你UnsupportedOperationException
,但所需的異常將包含在拋出的一箇中。
如果您想要斷言您的異常,則可以在調用異常被捕獲後拋出調用異常的目標。
例如,使用JUnit 4,你可以這樣做:
@Test(expected = UnsupportedOperationException.class)
public void utilityClassTest() throws NoSuchMethodException, IllegalAccessException, InstantiationException {
final Constructor<Utils> constructor = Utils.class.getDeclaredConstructor();
constructor.setAccessible(true);
try {
constructor.newInstance();
} catch (InvocationTargetException e) {
throw (UnsupportedOperationException) e.getTargetException();
}
}
不要。構造函數是私有的。這就是你需要的。 Java強制其隱私。
不要測試平臺。
測試不可訪問的代碼的實際用例是實現100%的測試覆蓋率,以便無人再次查看該類。如果覆蓋率保持在95%,許多開發人員可能會試圖找出導致這個問題反覆出現的原因。 另外,Java在強制隱私方面很糟糕。 :) – thisismydesign
使用Reflection API – MrSmith42
這可能會怎樣?你有一個例子嗎? – JAM
你沒有。您使用私有構造函數測試該方法。 –