简体   繁体   English

无法使用 mocking 抛出异常 - 抛出的异常未被捕获

[英]Unable to use mocking to throw an exception - the thrown exception is not being caught

I have a method where I'd like to mock an exception being thrown so that the catch statement is entered:我有一个方法,我想模拟一个被抛出的异常,以便输入 catch 语句:

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.PowerMockito.when()行。 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.这会导致 function 在不触发异常的情况下运行。

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.仍然没有调用 catch 语句,类似于我之前得到的。

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. 通过像以前一样创建它,可以在存根之前调用实际方法。

As MessageDigest.getInstance() is a static method - you should prepare it for the test and use mockStatic(). 由于MessageDigest.getInstance()是静态方法-您应该为测试做准备,并使用mockStatic()。

Here is a good example of it: https://examples.javacodegeeks.com/core-java/powermockito/powermock-mock-static-method-example/ 这是一个很好的例子: 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 我的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>

As MessageDigest is a Java system class, you need to deal with them differently as per: https://github.com/powermock/powermock/wiki/Mock-System 由于MessageDigest是Java系统类,因此您需要按照以下方式分别处理它们: https : //github.com/powermock/powermock/wiki/Mock-System

So declare the test class in the @PrepareForTest annotation as follows: @PrepareForTest({MessageDigest.class, MyTest.class}) 因此,在@PrepareForTest批注中声明测试类,如下所示: @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 {

Might be worth doing it like this as well, without using power mockito and other annotations在不使用 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);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM