问题
I have a method where I'd like to mock an exception being thrown so that the catch statement is entered:
public static String func(String val) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
return Base64.encode(md5.digest(val.getBytes()));
} catch (NoSuchAlgorithmException toCatch) {
return "*";
}
}
The test I've written is this:
@Test
public void testFunc() throws Exception {
MessageDigest md5 = PowerMockito.mock(MessageDigest.class);
PowerMockito.when(md5.getInstance(anyString())).thenThrow(new NoSuchAlgorithmException());
Assert.assertEquals("*", func("in"));
}
However i'm getting:
java.security.NoSuchAlgorithmException: MessageDigest not available
on the PowerMockito.when() line. Which implies the exception has been through, but not caught? What am I doing wrong?
Update: I have tried the following modifications
@PrepareForTest({MessageDigest.class})
@Test
public void testFunc() throws Exception {
PowerMockito.mockStatic(MessageDigest.class);
PowerMockito.when(MessageDigest.getInstance(anyString())).thenThrow(new NoSuchAlgorithmException());
Assert.assertEquals("*", testFunc("in"));
}
This causes the function to run without triggering the exception.
And this:
@PrepareForTest({MessageDigest.class})
@Test
public void testFunc() throws Exception {
PowerMockito.mockStatic(MessageDigest.class);
MessageDigest md5 = PowerMockito.mock(MessageDigest.class);
PowerMockito.doThrow(new NoSuchAlgorithmException()).when(md5, "getInstance", anyString());
Assert.assertEquals("*", func("in"));
}
Still doesn't invoke the catch statement, similar to what I was getting before.
回答1:
Invert the stubbing:
doThrow(new NoSuchAlgorithmException()).when(md5, "getInstance", anyString())
By creating it the way you did, you call the actual method before it gets stubbed.
回答2:
As MessageDigest.getInstance() is a static method - you should prepare it for the test and use mockStatic().
Here is a good example of it: https://examples.javacodegeeks.com/core-java/powermockito/powermock-mock-static-method-example/
Hope that will help
Here is what i've written:
@RunWith(PowerMockRunner.class)
public class MyTest {
@Test
@PrepareForTest({MessageDigest.class})
public void testFunc() throws Exception {
mockStatic(MessageDigest.class);
when(MessageDigest.getInstance(anyString())).thenThrow(new NoSuchAlgorithmException());
assertEquals("*", func("in"));
}
public static String func(String val) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
return Base64.encode(md5.digest(val.getBytes()));
} catch (NoSuchAlgorithmException toCatch) {
return "*";
}
}
}
my pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
</dependencies>
回答3:
As MessageDigest is a Java system class, you need to deal with them differently as per: https://github.com/powermock/powermock/wiki/Mock-System
So declare the test class in the @PrepareForTest annotation as follows:
@PrepareForTest({MessageDigest.class, MyTest.class})
Not sure if this annotation works as method level as per your example, but it should at class level:
@RunWith(PowerMockRunner.class)
@PrepareForTest({MessageDigest.class, MyTest.class})
public class MyTest {
来源:https://stackoverflow.com/questions/55592345/unable-to-use-mocking-to-throw-an-exception-the-thrown-exception-is-not-being