【问题标题】:Receiving InvalidUseOfMatchersException when stubbing method存根方法时收到 InvalidUseOfMatchersException
【发布时间】:2014-05-21 21:42:22
【问题描述】:

我目前对 Mockito 有疑问。但首先这里是我的代码,它创建了 Mockito 抱怨的模拟:

    @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;
}

ClassWriter 和 ...Visitor 类来自 asm(因此,如果您想测试此设置,您只需导入 asm、junit 和 mockito 库)。当我调用 createMockedClassWriter() 时,会引发以下异常

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

被称为:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 

参数匹配器的使用无效! 预计 1 个匹配者,记录 2 个: -> 在 com.sportslivefinder.service.rest.classCreation.RestEndpointByteCodeGeneratorTest.createMockedClassWriter(RestEndpointByteCodeGeneratorTest.java:91) -> 在 com.sportslivefinder.service.rest.classCreation.RestEndpointByteCodeGeneratorTest.createMockedClassWriter(RestEndpointByteCodeGeneratorTest.java:91)

如果匹配器与原始值组合,则可能会发生此异常: //不正确: someMethod(anyObject(), "原始字符串"); 使用匹配器时,所有参数都必须由匹配器提供。 例如: //正确的: someMethod(anyObject(), eq("String by matcher"));

有关更多信息,请参阅 Matchers 类的 javadoc。

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)

如您所见,我尝试了不同风格的存根创建,但这似乎不是问题。

有人可以帮帮我吗?

您好, 帕斯卡

【问题讨论】:

  • RestEndpointByteCodeGeneratorTest.java的第91行是哪一行?
  • 另外,在调用createMockedClassWriter 之前运行了什么?让我们看看整个测试,而不仅仅是一些随机的 sn-ps。
  • @DavidWallace 第 91 行是帖子中指出的 when(...) 调用。我添加了整个测试,以便您更好地了解发生了什么。给你一个简短的概述。我正在测试一个从方法的参数创建字节码的模块。
  • 当您收到该消息时,您是否正在单独运行该测试?或者你是在一系列的测试中运行它吗?如果是后者,那么问题可能出在在此之前运行的测试之一中。 Mockito 有一个用于存储匹配器的内部结构,我怀疑该结构中可能有一些你在应该拥有的时候没有取出的东西。尝试运行just this test并告诉我错误是否仍然发生。
  • 不,我将此测试作为单个单元测试运行,所以这不应该是问题的原因

标签: java exception mocking mockito


【解决方案1】:

visitAnnotation 是最终方法,thus cannot be mocked

public final AnnotationVisitor visitAnnotation(String desc, boolean visible)

有关幕后发生的事情以及为什么会在该行出现异常的更多信息,请参阅“How do Mockito matchers work?”。

【讨论】:

  • 谢谢杰夫!这就是问题所在。我现在正在使用用于 mockito 的 powerMock API 运行,一切正常!
  • @user2764975 不客气!当您对收到的答案感到满意时,单击左侧投票按钮下方的复选框以“接受”答案,标记您的问题已得到充分回答,并显示哪个答案对您最有帮助。 (很快你也可以投票了。)祝你的项目好运!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多