[英]Exception when calling MessageDigest.getInstance(“SHA256”)
[英]Mocking MessageDigest.getInstance() to throw an exception
我得到了以下方法:
private MessageDigest getMessageDigest() {
try {
return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new Error(e);
}
}
為了獲得 100% 的代碼覆蓋率,我需要進入 catch 塊。 但我絕對不確定我該怎么做。 在這種情況下,是否有一些模擬框架可以幫助我? 如果是這樣 - 如何? 或者還有另一種方法而不必捕獲異常嗎?
MessageDigest 上的 getInstance 方法看起來像一個靜態方法。 靜態方法不能被模擬。 我同意棘輪的觀點,即您不應該以 100% 的代碼覆蓋率為目標,而應專注於測試具有復雜代碼的區域。
只是要對這個問題進行跟進,可以使用PowerMock來完成。
作為摘錄,這是我的工作代碼:
@RunWith(PowerMockRunner.class)
@PrepareForTest({MyClass.class, MessageDigest.class})
public class MyClassTest {
private MyClass myClass = new MyClass();
@Mock private MessageDigest messageDigestMock;
@Test
public void shouldDoMethodCall() throws Exception {
setupMessageDigest();
String value = myClass.myMethodCall();
// I use FestAssert here, you can use any framework you like, but you get
// the general idea
Assertions.assertThat(value).isEqualToIgnoringCase("hashed_value");
}
public void setupMessageDigest() throws Exception {
PowerMockito.mockStatic(MessageDigest.class);
when(MessageDigest.getInstance("SHA1")).thenReturn(messageDigestMock);
when(messageDigestMock.digest(Matchers.<byte[]>anyObject())).thenReturn("hashed_value".getBytes());
}
}
“MyClass”類將簡單地執行以下操作:
public class MyClass {
public String myMethodCall() {
return new String(MessageDigest.getInstance("SHA1").digest("someString".getBytes()));
}
}
在附加測試中,您可以編寫
when(MessageDigest.getInstance("SHA1")).thenThrow(new NoSuchAlgorithmException());
而不是我提到的返回,到達你的 catch 塊。
但是請注意,使用 PowerMock 有一些缺點。 它通常會使用更多的內存和更多的實例化時間,因此您的測試將運行更長時間。 對於這個特定的測試,它不會有太大的不同,但只是一個問題。
我會這樣寫:
try {
return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw (AssertionError)new AssertionError("unreachable").initCause(e);
}
並聲明因為catch塊不可達,所以不需要測試。
老實說,在這種情況下,您不需要覆蓋該代碼,它是不可訪問的樣板,以確保您不必擔心用戶代碼中的已檢查異常(如果您能解釋為什么 2錯過了百分比)
就我而言,我們的管道需要 100% 的覆蓋率,因此我執行了以下操作:
MessageDigest
的實例catch
子句中,拋出一個AssertionError("unreachable", e)
來表明絕對不可能到達這里jacocoTestReport
和jacocoTestCoverageVerification
任務,忽略jacoco.gradle
這個靜態類。 要了解如何排除內部類,請查看我的另一篇文章: 使用 Gradle 時如何忽略 Jacoco 中的內部靜態類(鏈接到另一篇關於如何在 Maven 中執行此操作的文章,以防您使用它)您的異常無法訪問,因為永遠不會拋出該異常。 我想像 Mockito這樣的東西做一些類似於以下的事情是合乎邏輯的:
doThrow(new NoSuchAlgorithmException()).when(MessageDigest.getInstance("MD5")); // this is psuedo code
但這仍然沒有多大意義。 您最好編寫如下代碼:
private static final MessageDigest MD5_DIGEST;
static {
try {
MD5_DIGEST = MessageDigest.getInstance("MD5");
///CLOVER:OFF
} catch (Exception e) {
// can't happen since MD5 is a known digest
}
///CLOVER:ON
}
public MessageDigest getMessageDigest() {
return MD5_DIGEST;
}
否則你需要修改你的方法以進行測試:
public MessageDigest getMessageDigest(String digest) throws NoSuchAlgorithmException {
return MessageDigest.getInstance(digest);
}
您可以創建一個包裝 MessageDigest 類:
@Component
public class MessageDigest {
public java.security.MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException {
return java.security.MessageDigest.getInstance(algorithm);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.