Mockito InvalidUseOfMatchersException при издевательстве над почтовым запросом - PullRequest
0 голосов
/ 29 мая 2020

Я новичок в 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. Поэтому я решил поиздеваться над почтовым методом. Для этого я разработал следующий тест:

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, но ни один из задействованных методов и классов не является частным, ни stati c. Понятия не имею, что еще попробовать. Я ценю любую помощь.

1 Ответ

0 голосов
/ 29 мая 2020

Поскольку вы высмеяли ResteasyWebTarget и не определили, каким должен быть возврат метода request(), вы получили это исключение.

Сначала вы должны имитировать запрос и вернуть его методу request() и определите поведение метода post() из mockedRequest

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