#java #unit-testing #junit #mocking #powermockito
#java #модульное тестирование #junit #издевательство #powermockito
Вопрос:
У меня есть метод, в котором я хотел бы имитировать генерируемое исключение, чтобы ввести оператор catch:
public static String func(String val) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
return Base64.encode(md5.digest(val.getBytes()));
} catch (NoSuchAlgorithmException toCatch) {
return "*";
}
}
Тест, который я написал, заключается в следующем:
@Test
public void testFunc() throws Exception {
MessageDigest md5 = PowerMockito.mock(MessageDigest.class);
PowerMockito.when(md5.getInstance(anyString())).thenThrow(new NoSuchAlgorithmException());
Assert.assertEquals("*", func("in"));
}
Однако я получаю:
java.security.NoSuchAlgorithmException: MessageDigest not available
в PowerMockito.when()
строке. Что подразумевает, что исключение прошло, но не перехвачено? Что я делаю не так?
Обновление: я попробовал следующие модификации
@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"));
}
Это приводит к запуску функции без запуска исключения.
И это:
@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"));
}
По-прежнему не вызывает оператор catch, аналогичный тому, что я получал раньше.
Ответ №1:
Инвертировать блокировку:
doThrow(new NoSuchAlgorithmException()).when(md5, "getInstance", anyString())
Создавая его так, как вы это делали, вы вызываете фактический метод до того, как он будет заблокирован.
Комментарии:
1. вы поставили @PrepareForTest({MessageDigest.class } на уровне класса?
2. ДА. Никакого эффекта.
Ответ №2:
Поскольку MessageDigest.getInstance() является статическим методом — вы должны подготовить его к тестированию и использовать mockStatic().
Вот хороший пример этого:https://examples.javacodegeeks.com/core-java/powermockito/powermock-mock-static-method-example /
Надеюсь, это поможет
Вот что я написал:
@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 "*";
}
}
}
мой 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>
Комментарии:
1. Я делаю это сейчас, но это все еще происходит: @PrepareForTest({MessageDigest.class }) @Test public void TestFunc() выдает исключение { PowerMockito.mockStatic(MessageDigest.class ); MessageDigest md5 = PowerMockito.mock(MessageDigest.class ); PowerMockito. doThrow(new NoSuchAlgorithmException()).when(md5, «getInstance», anyString()); Assert.assertEquals(«*», func(«in»)); }
2. @JohnBergqvist не могли бы вы предоставить обновленный код?
3. Если вы используете PowerMockRunner, то это должно сработать. Я скоро обновлю свой ответ своими результатами
4. @JohnBergqvist пожалуйста, проверьте еще раз
Ответ №3:
Поскольку MessageDigest
это системный класс Java, вам нужно обращаться с ними по-разному в соответствии с:https://github.com/powermock/powermock/wiki/Mock-System
Поэтому объявите тестовый класс в @PrepareForTest
аннотации следующим образом: @PrepareForTest({MessageDigest.class, MyTest.class})
Не уверен, работает ли эта аннотация на уровне метода в соответствии с вашим примером, но это должно быть на уровне класса:
@RunWith(PowerMockRunner.class)
@PrepareForTest({MessageDigest.class, MyTest.class})
public class MyTest {
Ответ №4:
Возможно, стоит сделать это так же, без использования power mockito и других аннотаций
try (MockedStatic<MessageDigest> messageDigestMockedStatic = Mockito.mockStatic(MessageDigest.class)) {
messageDigestMockedStatic.when(() -> MessageDigest.getInstance(anyString()))
.thenThrow(new NoSuchAlgorithmException());
String input = "hello world";
try {
var digest = MessageDigest.getInstance(SHA_256_DIGEST_TYPE);
byte[] encodedHash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
return bytesToHex(encodedHash);
fail("Expected IllegalArgumentException to be thrown, but got hash value: " hash);
} catch (IllegalArgumentException e) {
// Verify that the exception message contains the expected error message
assertTrue(e.getMessage().contains("Invalid hash digest algorithm"));
// Verify that the cause of the IllegalArgumentException is a NoSuchAlgorithmException
assertTrue(e.getCause() instanceof NoSuchAlgorithmException);
}
}