java - 模拟 post 请求时 Mockito InvalidUseOfMatchersException

标签 java java-8 mockito junit4

我对mockito完全陌生,我已经尝试了很多在网上找到的解决方案,但我仍然无法解决这个问题。我什至不确定是什么原因造成的。我需要为一个非常成熟的代码创建一个模拟测试,我不允许更改该代码。我需要模拟的代码部分向服务器发送一个发布请求。我以更简单的方式重新创建了代码,但不幸的是,它仍然相当长。假设我有 ClassA,它调用 api,如下所示并返回一个整数。

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;

import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;

import com.fasterxml.jackson.databind.ObjectMapper;

public class ClassA {

    public int moveActual(String path) throws IOException {
        Response wsResponse = null;
        String newHome = "0" ;
        ResteasyClient httpClient = new ResteasyClientBuilder().connectionPoolSize(1)
                .establishConnectionTimeout(10, TimeUnit.SECONDS).socketTimeout(10, TimeUnit.SECONDS).build();
        ResteasyWebTarget target = httpClient.target(path) ;

        Map<String, Object> request = new HashMap<>();
        request.put("operation", "dislocation");
        request.put("direction", "right");
        request.put("amount", "2");
        request.put("unit", "metric");
        String requestJson = new ObjectMapper().writeValueAsString(request);

        wsResponse = target.request().post(Entity.entity(requestJson, "application/json"));
        String responseString = wsResponse.readEntity(String.class);
        ObjectMapper responseMapper = new ObjectMapper();
        @SuppressWarnings("unchecked")
        Map<String, Object> response = (Map<String, Object>) responseMapper.readValue(responseString, Map.class);

        if (response != null) {
            newHome = (String) response.get("coordinate");
        }
        // In the real code there is much more code here.
        return Integer.parseInt(newHome) ;
    }
}

我需要模拟服务器来测试 moveActual 方法。所以我决定模拟 post 方法。为此,我提出了以下测试:

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.BDDMockito.given;

import java.util.HashMap;
import java.util.Map;

import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import externalTests.ClassA;

@RunWith(MockitoJUnitRunner.class)
public class DispositionMockTest {

    @Mock
    ResteasyWebTarget targetMock;

    @InjectMocks
    ClassA classA;

    @Test
    public void dispositionTest() throws Exception {
        // Given
        Map<String, Integer> outcomeMap = new HashMap<String, Integer>() ;
        outcomeMap.put("coordinate", 4) ;
        Response resp = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).entity(outcomeMap).build() ;
        given(targetMock.request().post(ArgumentMatchers.isA(Entity.class))).willReturn(resp) ;

        // When
        int result = classA.moveActual("url") ;

        // Then
        assertEquals(4, result);
    }

}

但是,无论我做什么,我都会收到以下错误。

java.lang.NullPointerException
    at externalTests.DispositionMockTest.dispositionTest(DispositionMockTest.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.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.mockito.internal.runners.DefaultInternalRunner$1$1.evaluate(DefaultInternalRunner.java:46)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:77)
    at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:83)
    at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
    at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced or misused argument matcher detected here:

-> at externalTests.DispositionMockTest.dispositionTest(DispositionMockTest.java:42)

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
    verify(mock).someMethod(contains("foo"))

This message may appear after an NullPointerException if the last matcher is returning an object 
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
    when(mock.get(any())); // bad use, will raise NPE
    when(mock.get(anyInt())); // correct usage use

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.

    at org.mockito.internal.runners.DefaultInternalRunner$1$2.testFinished(DefaultInternalRunner.java:68)
    at org.junit.runner.notification.SynchronizedRunListener.testFinished(SynchronizedRunListener.java:56)
    at org.junit.runner.notification.RunNotifier$7.notifyListener(RunNotifier.java:190)
    at org.junit.runner.notification.RunNotifier$SafeNotifier.run(RunNotifier.java:72)
    at org.junit.runner.notification.RunNotifier.fireTestFinished(RunNotifier.java:187)
    at org.junit.internal.runners.model.EachTestNotifier.fireTestFinished(EachTestNotifier.java:38)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:331)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:77)
    at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:83)
    at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
    at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)

我尝试过 @spy 而不是 @mock 以及其他匹配器,例如 ArgumentMatchers.any(Entity.class)ArgumentMatchers .any() 但无济于事。我正在研究 powermock,但所涉及的方法和类都不是私有(private)的,也不是静态的。我不知道还能尝试什么。我感谢任何帮助。

最佳答案

因为您模拟了 ResteasyWebTarget 并且没有定义 request() 方法的返回内容,所以您得到了该异常。

您应该首先模拟请求并将其返回到 request() 方法,并从 mockedRequest 定义到 post() 方法的行为

when(targetMock.request()).thenReturn(mockedRequest);
when(mockedRequest.post(any(Entity.class))).thenReturn(resp) ;

关于java - 模拟 post 请求时 Mockito InvalidUseOfMatchersException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62090900/

相关文章:

java - 如何更新作为 Spring Security ACL 一部分的 acl_sid 表中的用户名?

java - 如何在 junit java 项目中导入 Web 应用程序

java - 如何解决 Mockito 参数匹配问题?

Java 使用 Mockito 验证 void 方法调用 n 次

java - 顶点 : handling POST body is so slow

java - 为什么这个 Java 程序没有显示我期望的结果?

java - 从文件末尾读取第 n 行

java - java.time.Duration 中的错误

java - 解析 LocalDateTime (Java 8) 时无法从 TemporalAccessor 获取 LocalDateTime

java - 使用 Java 8 流如何将 Map<String, List<Something>> 转换为 Map<String, Integer>?