0

I currently have a problem with Mockito. But first of all here is my code which creates the mocks Mockito complains about:

    @Test
public void testRestEndpointGeneration() {
    //Create a mocked classWriter to control the classWriter calls
    ClassWriter classWriter = createMockedClassWriter();
    //Create the list of annotated method parameters which should be used to generate the class
    List<AnnotatedMethodParameter> methodParameters = new ArrayList<>();
    methodParameters.add(new AnnotatedMethodParameter("testContext", "Ljavax/ws/rs/core/SecurityContext;", "Ljavax/ws/rs/core/SecurityContext;", ParameterType.CONTEXT));
    methodParameters.add(new AnnotatedMethodParameter("testMatrix", "Ljava/lang/Integer;", "Ljava/lang/Integer;", ParameterType.MATRIXPARAM));
    methodParameters.add(new AnnotatedMethodParameter("testForm", "Ljava/lang/Double;", "Ljava/lang/Double;", ParameterType.FORMPARAM));

    RestEndpointByteCodeGenerator.createClassByteCode("EndpointGenerationTest",
            "test/{testPath}",
            HttpMethod.GET,
            new String[]{"application/json", "application/xml"},
            new String[]{"application/json", "application/xml"},
            methodParameters,
            new MethodParameter("Ljava/util/Map;", "Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;"),
            classWriter);

    AnnotationVisitor annotationVisitor = classWriter.visitAnnotation("", true);
    FieldVisitor fieldVisitor = classWriter.visitField(1, "", "", null, null);
    MethodVisitor methodVisitor = classWriter.visitMethod(1, null, null, null, null);
    //Now check that the methods on the classWriter were correctly invoked
    InOrder inOrder = inOrder(classWriter);
    inOrder.verify(classWriter).visit(V1_7, ACC_PUBLIC + ACC_SUPER, "EndpointGenerationTest", null, "com/sportslivefinder/service/rest/generatedEndpoints/RestEndpointParent", null);
    inOrder.verify(classWriter).visitAnnotation("Ljavax/ws/rs/Path;", true);
    inOrder.verify(classWriter).visitField(ACC_PRIVATE + ACC_FINAL, "processor", "Lorg/apache/camel/Processor;", null, null);
    inOrder.verify(classWriter).visitMethod(ACC_PUBLIC, "processRequest", "(Ljavax/ws/rs/core/SecurityContext;Ljava/lang/Integer;Ljava/lang/Double;Ljava/util/Map;)Ljavax/ws/rs/core/Response;",
            "(Ljavax/ws/rs/core/SecurityContext;Ljava/lang/Integer;Ljava/lang/Double;Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;)Ljavax/ws/rs/core/Response;", null);

    inOrder = inOrder(annotationVisitor);
    inOrder.verify(annotationVisitor).visit("value", "test/{testPath}");
    inOrder.verify(annotationVisitor).visitEnd();
    inOrder.verify(annotationVisitor).visitEnd();
    for(int i = 0; i < 1; i++){
        inOrder.verify(annotationVisitor).visitArray("value");
        inOrder.verify(annotationVisitor).visit(null, "application/json");
        inOrder.verify(annotationVisitor).visit(null, "application/xml");
        inOrder.verify(annotationVisitor).visitEnd();
        inOrder.verify(annotationVisitor).visitEnd();
    }
    inOrder.verify(annotationVisitor).visit("value", "/");
    inOrder.verify(annotationVisitor).visitEnd();
    inOrder.verify(annotationVisitor).visitEnd();
    inOrder.verify(annotationVisitor).visit("value", "testMatrix");
    inOrder.verify(annotationVisitor).visitEnd();
    inOrder.verify(annotationVisitor).visit("value", "testForm");
    inOrder.verify(annotationVisitor).visitEnd();

    inOrder = inOrder(fieldVisitor);
    inOrder.verify(fieldVisitor).visitEnd();

    inOrder = inOrder(methodVisitor);
    inOrder.verify(methodVisitor).visitAnnotation("Ljavax/ws/rs/GET;", true);
    inOrder.verify(methodVisitor).visitAnnotation("Ljavax/ws/rs/Produces;", true);
    inOrder.verify(methodVisitor).visitAnnotation("Ljavax/ws/rs/Consumes;", true);
    inOrder.verify(methodVisitor).visitAnnotation("Ljavax/ws/rs/Path;", true);

}

private ClassWriter createMockedClassWriter(){
    ClassWriter classWriter = mock(ClassWriter.class);
    final AnnotationVisitor annotationVisitor = createMockedAnnotationVisitor();
    final MethodVisitor methodVisitor = createMockedMethodVisitor(annotationVisitor);
    final FieldVisitor fieldVisitor = mock(FieldVisitor.class);

    when(classWriter.visitAnnotation(anyString(), anyBoolean())).thenReturn(annotationVisitor);
    doReturn(annotationVisitor).when(classWriter).visitAnnotation(anyString(), anyBoolean());
    doReturn(fieldVisitor).when(classWriter).visitField(anyInt(), anyString(), anyString(), anyString(), any());
    doReturn(methodVisitor).when(classWriter).visitMethod(anyInt(), anyString(), anyString(), anyString(), any(String[].class));

    return classWriter;
}

private AnnotationVisitor createMockedAnnotationVisitor(){
    final AnnotationVisitor visitor = mock(AnnotationVisitor.class);

    doReturn(visitor).when(visitor).visitArray(anyString());

    return visitor;
}

private MethodVisitor createMockedMethodVisitor(AnnotationVisitor annotationVisitor){
    MethodVisitor methodVisitor = mock(MethodVisitor.class);

    doReturn(annotationVisitor).when(methodVisitor).visitAnnotation(anyString(), anyBoolean());

    return methodVisitor;
}

The ClassWriter and the ...Visitor classes are from asm (so if you want to test this setup you just need to import the asm, junit and mockito library). When I'm calling createMockedClassWriter() the following Exception is thrown when

when(classWriter.visitAnnotation(anyString(), anyBoolean())).thenReturn(annotationVisitor); 

is called:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 

Invalid use of argument matchers! 1 matchers expected, 2 recorded: -> at com.sportslivefinder.service.rest.classCreation.RestEndpointByteCodeGeneratorTest.createMockedClassWriter(RestEndpointByteCodeGeneratorTest.java:91) -> at com.sportslivefinder.service.rest.classCreation.RestEndpointByteCodeGeneratorTest.createMockedClassWriter(RestEndpointByteCodeGeneratorTest.java:91)

This exception may occur if matchers are combined with raw values: //incorrect: someMethod(anyObject(), "raw String"); When using matchers, all arguments have to be provided by matchers. For example: //correct: someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.

at org.objectweb.asm.ClassWriter.visitAnnotation(Unknown Source)
at com.sportslivefinder.service.rest.classCreation.RestEndpointByteCodeGeneratorTest.createMockedClassWriter(RestEndpointByteCodeGeneratorTest.java:91)
at com.sportslivefinder.service.rest.classCreation.RestEndpointByteCodeGeneratorTest.testRestEndpointGeneration(RestEndpointByteCodeGeneratorTest.java:28)

As you can see, I've tried different styles of the stub creation but this seems not the problem.

Can anybody help me out here?

Greetings, Pascal

user2672165
  • 2,986
  • 19
  • 27
htipk
  • 109
  • 3
  • 10
  • Which line is line 91 of RestEndpointByteCodeGeneratorTest.java? – Dawood ibn Kareem May 21 '14 at 21:48
  • Also, what has run before the call to `createMockedClassWriter`? Let's see the whole test, not just a few random snippets. – Dawood ibn Kareem May 21 '14 at 21:50
  • @DavidWallace line 91 is the when(...) call which is pointed out in the post. I'v added the whole test so that you can better understand whats going on. To give you a short overview. I'm testing a module which creates byte code from the parameter of the method. – htipk May 21 '14 at 22:34
  • Are you running that test in isolation when you get that message? Or are you running it in a whole series of tests? If it is the latter, then the problem might be in one of the tests that runs before this one. Mockito has an internal structure for storing matchers, and I suspect that there may be something left over in that structure that you didn't pull out when you should have. Try running _just this test_ and tell me whether the error still occurs. – Dawood ibn Kareem May 21 '14 at 22:41
  • No, I'm running this test as a single unit test so this should not be the cause of the problem – htipk May 21 '14 at 22:48
  • OK, I'm going to have to set this up on my laptop and run it to see what's happening. I can't do that for several hours. I will ask you one more question though. Is there a reason why you're doing the same stubbing twice? Lines 91 and 92 are doing exactly the same stubbing operation, so you definitely only need one of them. – Dawood ibn Kareem May 21 '14 at 23:01
  • You're right they are doing the same and no there is no need for that ;) Must be happened when I tried the different syntaxes for method stubbing to see if this helps – htipk May 22 '14 at 05:39

1 Answers1

2

visitAnnotation is a final method, and thus cannot be mocked.

public final AnnotationVisitor visitAnnotation(String desc, boolean visible)

For more information about what's going on under the hood, and why you get that exception on that line, see "How do Mockito matchers work?".

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • Thanks Jeff! That was the problem. I'm now running with the powerMock API for mockito and it all works fine! – htipk May 23 '14 at 13:11
  • @user2764975 You're welcome! When you're satisfied with the answers you've received, click the check box under the voting buttons to the left to "accept" an answer, marking that your question was answered sufficiently and showing which answer was most helpful to you. (Soon you'll be able to vote, too.) Good luck on your project! – Jeff Bowman May 23 '14 at 15:05