java.lang.NullPointerException 在 Url 模拟测试中

java.lang.NullPointerException on Url mock tests

我对 Url 连接的测试工作正常。然后 1 个月后,我 运行 应用程序中的所有测试和 URL 连接测试都失败了,我不知道为什么,因为我没有更改此 class。拜托,有人可以看看这个测试吗?

测试现在抛出 java.lang.NullPointerException

测试的最初想法来自:https://programmingproblemsandsolutions.blogspot.com/2019/04/abstractmethoderror-is-thrown-on.html

测试:

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

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import static org.junit.jupiter.api.Assertions.assertTrue;

@RunWith(PowerMockRunner.class)
@PrepareForTest({URL.class})
class JsonOutputFromURLImplTest
{
    @Test
    void currencyValuesNBP() throws IOException
    {
        class UrlWrapper
        {
            private URL url;

            public UrlWrapper(String spec) throws MalformedURLException
            {
                url = new URL(spec);
            }

            private URLConnection openConnection() throws IOException
            {
                return url.openConnection();
            }
        }

        UrlWrapper url = PowerMockito.mock(UrlWrapper.class);
        HttpURLConnection httpURLConnection = Mockito.mock(HttpURLConnection.class);
        PowerMockito.when(url.openConnection()).thenReturn(httpURLConnection);
        assertTrue(url.openConnection() instanceof HttpURLConnection);
    }
}

测试class:

@Service
@NoArgsConstructor
public class JsonOutputFromURLImpl implements JsonOutputFromURL
{

    @Override
    public String currencyValuesNBP(String APIUrl) throws ConnectionWithApiEX
    {
        String jsonOutput = null;

        try {
            URL url = new URL(APIUrl);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setRequestMethod("GET");
            httpURLConnection.setRequestProperty("Content-Type", "application/json");

            InputStreamReader inputStreamReader = new InputStreamReader(httpURLConnection.getInputStream());
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            jsonOutput = bufferedReader.readLine();

            httpURLConnection.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }

        if(jsonOutput != null)
            return jsonOutput;

        throw new ConnectionWithApiEX(APIUrl);
    }
}
java.lang.NullPointerException
    at com.bartosz.kolej.stock.service.impl.JsonOutputFromURLImplTestUrlWrapper.openConnection(JsonOutputFromURLImplTest.java:36)
    at com.bartosz.kolej.stock.service.impl.JsonOutputFromURLImplTestUrlWrapper.access[=14=]0(JsonOutputFromURLImplTest.java:25)
    at com.bartosz.kolej.stock.service.impl.JsonOutputFromURLImplTest.currencyValuesNBP(JsonOutputFromURLImplTest.java:42)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:532)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod(TestMethodTestDescriptor.java:170)
    at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:108)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:112)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:112)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:188)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

简短回答:将您的 UrlWrapper.openConnection 标记为 public,您就可以开始了。

其次:您没有在服务中测试任何方法class,它的代码无关紧要。

第三:PowerMock可以模拟私有方法,它对你不起作用的原因很复杂。

  • 您使用 Junit 5 注释。使用 JUnit4 和 JUnit5 注释时同一测试的行为不同

考虑以下 class

public static class MyClass {
    public String A() {
        System.out.println("A called");
        return "A";
    }

    private String B() {
        System.out.println("B called");
        return "B";
    }

}

使用 Junit4 注释:

@org.junit.Test
public void testMockPrivateMethod() throws Exception {
    MyClass myClass = PowerMockito.mock(MyClass.class);
    PowerMockito.when(myClass.B()).thenReturn("mockB");
    //PowerMockito.when(myClass, "B").thenReturn("mockB");
    System.out.println(myClass.B());
}

Output:
mockB

使用 Junit5 注释:

@org.junit.jupiter.api.Test
public void testMockPrivateMethod() throws Exception {
    MyClass myClass = PowerMockito.mock(MyClass.class);
    PowerMockito.when(myClass.B()).thenReturn("mockB");
    System.out.println(myClass.B());
}

Output:
B called

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

这是因为您需要字节码检测来模拟私有方法。不幸的是,Junit5 引擎不使用 PowerMockRunner(它有自己的扩展机制)。请注意,您可以将 Junit4 注释与 Junit5 一起使用,但需要导入 vintage runner。

如您所见,正在调用真正的方法。不幸的是,您没有看到异常,因为您的方法抛出 NPE。