Powermockito не дразнит конструктор URL в методе URI.toURL () - PullRequest
0 голосов
/ 16 апреля 2020

Этот модульный тест не пройден.

package com.abc;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.net.URI;
import java.net.URL;

import static org.junit.Assert.assertEquals;

@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PrepareForTest({URI.class})
public class ITest2 {
    @Test
    public void test5() throws Exception {
        URI uri = new URI("http://www.google.com");

        final URL resourceUrl = ClassLoader.getSystemClassLoader().getResource("static/abc.png"); //EXISTS

        PowerMockito.whenNew(URL.class).withArguments(
                "http://www.google.com")
                .thenReturn(resourceUrl);

        URL url = uri.toURL(); // <--- At this point, url should be == resourceUrl

        assertEquals(resourceUrl, url); // <--- url is http://www.google.com and not ".../static/abc.png"
    }
}

Этот модульный тест не пройден.

java.lang.AssertionError: 
Expected :file:/Users/hidden/target/classes/static/abc.png
Actual   :http://www.google.com
<Click to see difference>

Знаете ли вы, почему url! = ResourceUrl? Чего мне не хватает?

Вот код URI.toURL ():

public URL toURL()
    throws MalformedURLException {
    if (!isAbsolute())
        throw new IllegalArgumentException("URI is not absolute");
    return new URL(toString());
}

Использование Mockito 2.15 и Powermock 2.0.7.

Спасибо.

Обновление:

Добавление этих также не помогает. Просто взломать.

PowerMockito.whenNew(URL.class).withArguments(
        eq("http://www.google.com"))
        .thenReturn(resourceUrl);

PowerMockito.whenNew(URL.class).withArguments(Mockito.anyString()).thenReturn(resourceUrl);
PowerMockito.whenNew(URL.class).withArguments(any()).thenReturn(resourceUrl);
PowerMockito.whenNew("java.net.URL").withArguments(any()).thenReturn(resourceUrl);

PowerMockito.whenNew(URL.class).withParameterTypes(String.class)
        .withArguments("http://www.google.com")
        .thenReturn(resourceUrl);

PowerMockito.whenNew(URL.class).withAnyArguments().thenReturn(resourceUrl);

PowerMockito.whenNew(URL.class).withNoArguments().thenReturn(resourceUrl);

1 Ответ

0 голосов
/ 22 апреля 2020

Из FAQ :

Вопрос:

Я не могу макетировать классы из java .lang, java. net, java .io или другие системные классы, почему?

Ответ:

Это потому, что они загружены Java bootstrap classloader и не может быть обработан байт-кодом загрузчиком классов PowerMock . Поскольку в PowerMock 1.2.5 есть обходной путь, ознакомьтесь с этим простым примером, чтобы увидеть, как это делается.

Обратите внимание, что ссылка на пример не работает, она должна быть this one вместо


user674669 wrote:

Я перехватываю конструктор класса URL, который происходит в классе URI.

Вы пытаетесь это сделать. Однако это завершается с ошибкой (и вместо этого создается реальный объект).

user674669 wrote:

Итак, я готовлю URI с использованием аннотации PrepareForTest.

java.net.URI - системный класс. Как упоминалось выше, PowerMockito не может манипулировать байт-кодом для него, поэтому он не будет иметь никакого эффекта. Вместо этого вам придется настроить байт-код другого класса, что подразумевает, что вам нужно определить другой класс в аннотации @PrepareForTest.


Рабочий пример для случая, упомянутого в связанная статья :

Протестировано с powermock 2.0.7, mockito 3.3.3, junit 4

public class ClassUnderTest {
    public InputStream method(boolean param, URI uri) throws Exception {
        String scheme = param ? "https" : "http";
        URI replacedUri = new URI(scheme, uri.getAuthority(), uri.getPath(), uri.getQuery(), uri.getFragment());
        return replacedUri.toURL().openStream();
    }
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassUnderTest.class)
public class MyTest { 

    @Test
    public void testMethod() throws Exception { 

        URI uri = new URI("blah://localhost");
        FileInputStream fis = new FileInputStream(new File(".", "existing.file"));

        URI uriMock = PowerMockito.mock(URI.class); 
        URL urlMock = PowerMockito.mock(URL.class); 

        PowerMockito.whenNew(URI.class).withAnyArguments().thenReturn(uriMock); 
        Mockito.when(uriMock.toURL()).thenReturn(urlMock); 
        Mockito.when(urlMock.openStream()).thenReturn(fis); 

        ClassUnderTest testObject = new ClassUnderTest(); 
        InputStream is = testObject.method(false, uri);

        Assert.assertEquals(fis, is);
    }
}

Это работает, потому что байт-код ClassUnderTest модифицируется и вместо него создается реальный объект URI.

...