Java PowerMock:模拟具有不同参数的同一方法的多个调用行为异常

Java PowerMock:模拟具有不同参数的同一方法的多个调用行为异常,java,mockito,powermock,powermockito,Java,Mockito,Powermock,Powermockito,我对Mockito很陌生,有一个问题花费了我很多时间。下面是我的问题陈述和可执行代码 问题 每当我试图用不同参数模拟同一方法的多个行为时,mockito/powermockito都会使用我在单个测试中为测试定义的最后一个行为。下面是我的示例,Service类有一个静态foo方法,该方法正从我的方法调用(我要测试)使用不同参数的次数 它抛出ClassCastException并想将breresponse转换为AResponse,因为我上次对breponse的存根是因为breponse而我第一次调用

我对Mockito很陌生,有一个问题花费了我很多时间。下面是我的问题陈述和可执行代码

问题 每当我试图用不同参数模拟同一方法的多个行为时,mockito/powermockito都会使用我在单个测试中为测试定义的最后一个行为。下面是我的示例,
Service
类有一个静态
foo
方法,该方法正从我的方法调用(我要测试)使用不同参数的次数

它抛出
ClassCastException
并想将
breresponse
转换为
AResponse
,因为我上次对
breponse
的存根是因为
breponse
而我第一次调用
foo
是在
ClassUnderTest.execute()
中要求
AResponse

示例代码 例外情况: 猜测:我认为你对那些嘲弄的规格有错误的理解

你写道:

when(Service.foo(any(), new ARequest(any(), "A")))
但这真的有意义吗?您想说:调用foo()时,第一个参数无关紧要。第二个必须是某个请求对象。更具体地说,您想说:一个ARequest对象在与其他对象进行比较时,忽略了它的“数字”部分。但是:这不是这里的情况。你必须在那里提供一个真实的对象,而不是一个“指定的”对象

我的意思是:稍后,在运行时,模拟框架看到调用了foo(),然后开始寻找匹配的参数。但是,模拟框架如何理解您想要匹配包含任意数字的请求对象呢

换句话说:我假设Lombok@Data将生成equals方法。当然,这些将比较这些类中的所有元素

所以,我认为解决方案可以是使用特定的请求对象,比如

when(Service.foo(any(), new ARequest(1, "A")))
然后确保数字ID始终以1的形式输入

或者,您可以尝试生成equals()方法,这些方法只比较请求的“name”部分

长话短说:我认为,当规范出错时,您就得到了这些规范的语义

我认为发生的事情是,
newarequest(any(),“A”)
只是创建了某种类型的ARequest对象,然后PowerMockito将尝试与之相等;结果可能一直是“错误的”

最后:我希望您理解,您将两个字节码操作框架混为一谈,有一定的可能会导致异常的问题?我见过很多次PowerMock(ito)导致奇怪的失败(因为它以某种方式改变了您的字节码);然后在上面加上龙目山的东西?你甚至会去模拟静态调用?因此,我个人的建议是:看看是否有机会将static方法转换为某个实例方法(您甚至可以在静态调用周围放置自己的包装器),这样您就可以在这里使用普通Mockito而不是PowerMockito

为您的自定义对象使用
eq()
匹配器,通过进行此更改,您的函数模拟将看起来链接:

when(Service.foo(any(), eq(new ARequest(1, "A")))).thenReturn(new AResponse(1, "passed"));
when(Service.foo(any(), eq(new ARequest(2, "2A")))).thenReturn(new AResponse(2, "passed"));
when(Service.foo(any(), eq(new BRequest(1, "B")))).thenReturn(new BResponse(112, "passed"));
您应该在
请求
对象中指定参数,并从内部删除
any()

另一种选择是写下你的答案并在里面检查类型,如:

when(mock.foo(anyString(), anyObject())).thenAnswer(
    invocation -> {
        Object argument = invocation.getArguments()[1];
        if (argument.equals(new ARequest(1, "A"))) {
            return new AResponse(1, "passed");
        } else if (argument.equals(new ARequest(2, "2A"))) {
            return new AResponse(2, "passed");
        } else if (argument.equals(new BRequest(1, "B"))) {
            return new BResponse(112, "passed");
        }
        throw new InvalidUseOfMatchersException(
            String.format("Argument %s does not match", argument)
        );
    }
);
when(Service.foo(any(), eq(new ARequest(1, "A")))).thenReturn(new AResponse(1, "passed"));
when(Service.foo(any(), eq(new ARequest(2, "2A")))).thenReturn(new AResponse(2, "passed"));
when(Service.foo(any(), eq(new BRequest(1, "B")))).thenReturn(new BResponse(112, "passed"));
when(mock.foo(anyString(), anyObject())).thenAnswer(
    invocation -> {
        Object argument = invocation.getArguments()[1];
        if (argument.equals(new ARequest(1, "A"))) {
            return new AResponse(1, "passed");
        } else if (argument.equals(new ARequest(2, "2A"))) {
            return new AResponse(2, "passed");
        } else if (argument.equals(new BRequest(1, "B"))) {
            return new BResponse(112, "passed");
        }
        throw new InvalidUseOfMatchersException(
            String.format("Argument %s does not match", argument)
        );
    }
);