2015-02-24 4 views
2

После добавления powermock (1.5.6 в сочетании с EasyMock 3.2) для моего текущего проекта (JDK 1.6.0) я получаю несколько тестовых сбоев в методах испытаний, которые работали прекрасно, прежде чем:Powermock ImageIO UnsatisfiedLinkError

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 страница уже имеет bug с 2009 года, но не исправить и не обходной путь. (Возвращение к 32Bit - это нонсенс, поскольку эти методы работают без powermock). Так кто-нибудь знает, как это исправить?

Обновление I: Переключение на 32 бит не является вариантом, и кроме того, это не проблема. Если я не использую PowerMock каждый тест отлично работает в моем 64-битном виртуальной машине Java ...

Update II: Ok вот запрошенная информация о

Update III: продлевал класс

  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) это работает. Если раскомментировано это, вызывается вышеуказанная ошибка (снова!)

+0

Часть проблемы, похоже, представляет собой разный загрузчик класса powermock. Если я добавлю @PowerMockIgnore ({"com.sun.imageio. *"}), Он, похоже, сможет сделать еще один шаг, но он все еще не работает ... – Lonzak

+0

Я считаю, что метод в Error является нативным методом , Что вы пытаетесь достичь здесь? Издеваться над ImageIO? – haraldK

+0

Я хотел издеваться над личным методом, поэтому я добавил для этого powerermock. После этого другие существующие тесты, которые преуспевают без powermock, должны работать по-прежнему - вот чего я пытаюсь достичь ... – Lonzak

ответ

7

Решение состоит в том, чтобы сказать 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 - возможно, он пытается для загрузки некоторой родной библиотеки).
+0

Я уже пробовал это до публикации здесь, но, к сожалению, он тоже не работает. Я обновил код выше (см. Update III), чтобы отразить ситуацию ... – Lonzak

+1

Теперь он должен работать с добавлением «javax.security». Обратите внимание на выражение '' javax.imageio. *, Javax.security. * "' Недействительно. –

+0

А, спасибо, что заметили это. Я сделал еще один шаг, но теперь какая-то другая вещь не работает ... нужно понять, что из нее ... – Lonzak