Невозможно использовать mocking для создания исключения — созданное исключение не перехватывается

#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);
        }
    }