【问题标题】:Powermock imageio UnsatisfiedLinkErrorPowermock imageio UnsatisfiedLinkError
【发布时间】:2015-02-24 14:50:51
【问题描述】:

在我当前的项目(jdk 1.6.0)中添加了 powermock(1.5.6 和 Easymock 3.2)之后,我在测试方法中遇到了一些测试失败,这些测试方法之前运行良好:

java.lang.UnsatisfiedLinkError: com.sun.imageio.plugins.jpeg.JPEGImageReader.initReaderIDs(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;)V

以下代码失败:

BufferedImage img = null;
try {
    img = ImageIO.read(this.getClass().getResourceAsStream("/example.jpg"));
}
catch (IOException e) {
    fail(e.getMessage());
}

powermock 页面自 2009 年以来已有 bug,但没有修复和解决方法。 (回到 32Bit 是无稽之谈,因为这些方法在没有 powermock 的情况下工作)那么有人知道如何解决这个问题吗?

更新一:切换到 32 位是没有选择的,除此之外这不是问题。如果我不使用 PowerMock,每个测试都可以在我的 64 位 JVM 中完美运行...

更新二:好的,这里是请求的信息

更新三:扩展类

  1. 要测试的类

    import java.awt.image.BufferedImage;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.security.GeneralSecurityException;
    import java.security.cert.X509Certificate;
    import javax.imageio.ImageIO;
    import sun.security.x509.CertificateIssuerName;
    import sun.security.x509.CertificateSubjectName;
    import sun.security.x509.X500Name;
    import sun.security.x509.X509CertImpl;
    import sun.security.x509.X509CertInfo;
    
    public class App {
        private X509Certificate certificate = null;
    
        public ByteArrayOutputStream readImage() {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedImage img = null;
    try {
        img = ImageIO.read(this.getClass().getResourceAsStream("/example.jpg"));
        ImageIO.write(img, "png", baos);
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    
    return baos;
    }
    
    public String readCertificate() throws Exception{
     this.certificate = generateCertificate();
     return this.certificate.getIssuerX500Principal().getName();
    }
    
    private static X509Certificate generateCertificate() throws   GeneralSecurityException, IOException{
          X509CertInfo info = new X509CertInfo();
          X500Name owner = new X500Name("CN=example.net");
          info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
          info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
          return new X509CertImpl(info);
     }   
    }
    
  2. 测试用例:

    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.powermock.core.classloader.annotations.PowerMockIgnore;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(App.class)
    @PowerMockIgnore("javax.imageio.*, javax.security.*") 
    public class AppTest {
    
     @Test
     public void testApp(){
         App test = new App();
         Assert.assertNotNull(test.readImage());
         Assert.assertEquals(284506, test.readImage().size());
     }
     @Test
     public void testCertificate() throws Exception{
       App test = new App();
       test.readCertificate();
     }
    }
    
  3. Maven 依赖:

    <dependencies>
        <!-- TEST -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.easymock</groupId>
            <artifactId>easymock</artifactId>
            <version>3.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>1.5.6</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-easymock</artifactId>
            <version>1.5.6</version>
            <scope>test</scope>
        </dependency>
    

因此,如果您评论该行: //@RunWith(PowerMockRunner.class) 这是工作。如果取消注释,则会抛出上述错误(再次!)

【问题讨论】:

  • 部分问题似乎是powermock的不同类加载器。如果我添加 @PowerMockIgnore({"com.sun.imageio.*"}) 似乎可以更进一步,但它仍然无法正常工作......
  • 我相信错误中的方法是本机方法。你想在这里达到什么目的?模拟 ImageIO?
  • 我想模拟一个私有方法 - 所以我为此添加了 powermock。之后,其他没有 powermock 成功的现有测试应该像以前一样工作 - 这就是我想要实现的......
  • 您可能会考虑使用 JMockit。它只是一个库,无论使用接口还是类,使用起来都非常简单且一致,我现在更喜欢它,而不是我以前最喜欢的 Mockito。 JMockit 使用 Java6 的字节码检测而不是 java.lang.reflect.Proxy 和 CGLIB。见jmockit.org
  • 您能否提供更多信息(依赖关系树,完整的测试类)。根据您发布的代码,我使用 easymock 3.2、powermock 1.5.6、junit 4.4 创建了一个测试 (PowerMockRunner),它可以工作。

标签: java powermock easymock javax.imageio


【解决方案1】:

解决方案是告诉 PowerMock 忽略所有与其自定义类加载器冲突的 JRE 类。 即在测试类中添加如下注解:

@PowerMockIgnore({"javax.imageio.*", "javax.security.*"})

(注意注解的value 属性采用正则表达式的数组;它不支持在单个字符串中使用多个逗号分隔的表达式。)

为什么需要这样做的解释是

  1. PowerMock 通过在自己的自定义类加载器中重新加载准备好的类(以及测试类)来运行;
  2. App 调用javax.imageio.ImageIO 时,它最终会尝试加载和初始化内部类com.sun.imageio.plugins.jpeg.JPEGImageReader,然后尝试从调用者 类加载一些其他com.sun.imageio 类装载机;和
  3. 类加载失败,因为 PowerMock 的自定义类加载器显然找不到那些 JRE 类(此时很难准确判断发生了什么,因为加载是由 JPEGImageReader 类中的本机方法完成的 - 也许它也尝试加载一些本机库)。

【讨论】:

  • 在发帖之前我已经尝试过了 - 但不幸的是它也不起作用。我确实更新了上面的代码(cp.Update III)以反映情况......
  • 现在应该可以工作了,加上“javax.security”。请注意表达式"javax.imageio.*, javax.security.*" 无效。
  • 啊,感谢您发现这一点。我又进了一步,但现在其他一些事情不起作用......必须弄清楚那个......
猜你喜欢
  • 1970-01-01
  • 2015-04-24
  • 2012-05-28
  • 2016-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多