Java 如何在Mockito中处理不匹配的参数?

Java 如何在Mockito中处理不匹配的参数?,java,junit,mockito,Java,Junit,Mockito,我喜欢做如下事情: .when( myMock.doSomething( Matchers.eq( "1" ) ) ) .thenReturn( "1" ) .othwerwise() .thenThrow( new IllegalArgumentException() ); 当然,代码> Objiste()/Case>方法不存在,只是为了显示我想要完成的事情。只使用相反的条件,即考虑您的示例本身。当您需要时,您可能希望使用not(eq()),否则: .w

我喜欢做如下事情:

.when( 
    myMock.doSomething(
        Matchers.eq( "1" )
    ) 
)
.thenReturn( "1" )
.othwerwise()
.thenThrow( new IllegalArgumentException() );

当然,<>代码> Objiste()/Case>方法不存在,只是为了显示我想要完成的事情。

只使用相反的条件,即考虑您的示例本身。当您需要

时,您可能希望使用
not(eq())
,否则

 .when( myMock.doSomething(Matchers.eq( "1" )))
     .thenReturn( "1" )
 .when( myMock.doSomething(not(Matchers.eq( "1" ))))
     .thenThrow( new IllegalArgumentException() );

您可以创建自己的应答实现,该实现将关注调用的参数:

myMock.doSomething(Mockito.any(String.class)).thenAnswer( myAnswer );
上述答案的实施可以做到以下几点:

public String answer(InvocationOnMock invocation) {
    if ("1".equals(invocation.getArguments()[0])) {
       return "1";
    }
    else {
       throw new IllegalArgumentException();
    }
} 
(轻微的免责声明,我从未亲自做过这件事,只是在javadoc中读到它)。。。如果模拟接口上的所有方法都可以使用相同的默认行为,则可以采用如下方式:

Foo myMock = Mockito.mock(Foo.class,new ThrowsExceptionClass(IllegalArgumentException.class));
Mockito.when(myMock.doSomething(Matchers.eq("1"))).thenReturn("1");
JavaDoc链接:和

或者,正如在中所讨论的,存根问题的顺序和最后匹配的赢家,所以您也可以这样做:

Foo myMock = Mockito.mock(Foo.class);
Mockito.when(myMock.doSomething(Matchers.any(String.class))).thenThrow(IllegalArgumentException.class);
Mockito.when(myMock.doSomething(Matchers.eq("1"))).thenReturn("1");

或者,您可以使用verify,如下所示:

when(myMock.doSomething("1")).thenReturn( "1" );
assertEquals(myMock.doSomething("1"),"1");
verify(myMock).doSomething("1")

使用java 8 lambda,您可以执行以下操作:

myMock.doSomething(Mockito.any(String.class)).thenAnswer(invocation -> {    
    Object arg = invocation.getArguments()[0];
    if ("1".equals(arg)) {
        return "1";
    }

    throw new IllegalArgumentException("Expected 1 but got " + arg);
});

@Charlie的公认答案所描述的方式(不再)起作用了。 当您尝试覆盖某个参数的常规抛出异常行为时,会触发第一条规则,并且您有一个异常(正如您所要求的)

要避免调用,可以使用
Mockito.doReturn()
方法:

Mockito.when(myMock.doSomething(any()))
    .thenThrow(IllegalArgumentException.class);
Mockito.doReturn("1").when(myMock).doSomething(eq("1"));
最初的问题是根据javadoc存在
doReturn()
的原因之一:

Here are those rare occasions when doReturn() comes handy:
<...some lines are skipped...>
Overriding a previous exception-stubbing:

hen(mock.foo()).thenThrow(new RuntimeException());
//Impossible: the exception-stubbed foo() method is called so RuntimeException is thrown.
when(mock.foo()).thenReturn("bar");

//You have to use doReturn() for stubbing:
doReturn("bar").when(mock).foo();
以下是doReturn()能派上用场的罕见情况:
覆盖以前的异常存根:
hen(mock.foo()).thenthow(newruntimeexception());
//不可能:调用异常存根foo()方法,因此引发RuntimeException。
when(mock.foo())。然后返回(“bar”);
//必须使用doReturn()进行存根:
doReturn(“bar”).when(mock).foo();

这种方法的问题是,每次我需要添加新的匹配器时,我都必须添加与该匹配器相反的匹配器。假设我可能有20个匹配器,这将需要我添加20个相反的条件。“真的没有更好的方法吗?”supertonsky想到简单Java。在普通Java中,
while
没有任何
,否则
。while的语法是:当条件满足时做某事。彼此彼此。我们安排Java代码来满足我们的需求。我们需要在这里应用类似的概念,我不同意。“while”是一个迭代构造,而不是一个条件构造。“when”更像是“if”这样的条件结构。我正在寻找一种类似于“else”的解决方案,而不是类似于另一个“if”的解决方案,该解决方案简单地逆转了前面的“if”的条件,即“if”只是被捕获。@supertonsky:我不是说,
when
与Java中的
while
完全相同。我所说的是,
的主体在满足条件时被执行,与
相同,而
的主体基于条件。我试图解释这种相似性,只是为了解释这里没有其他相似之处<代码>而仅用于示例。我不确定分歧在哪里。还有其他的结构可以用来实现你想要的东西。你可以用“while”来像“if”一样工作,反之亦然。如果存在更优雅的解决方案或提供了适当的构造,我只是不喜欢通过代码破解来工作。归根结底,这是关于为正确的工作使用正确的工具。我喜欢这个答案,尽管我已经扩展了一个匹配器来匹配其中一个参数,即映射。有没有一种方法可以使用我现有的matcher来对付invocation.getArguments()?如果正确理解您的问题,我会说将它(或它们)作为构造函数参数传递给您的答案实现,然后简单地针对适当的参数调用matcher.matches()。效果非常好。虽然我发现他们决定让最后一个matcher获胜是违反直觉的。这正是我更喜欢自定义答案实现方法的原因。我发现它更直接(也更直观)。有几个注意事项。您给出的第一个解决方案是好的,但是由于默认答案适用于mock的每个方法,因此如果您的测试在您正在测试的方法之外还调用了mock上的其他方法,那么您需要小心。我相当肯定您给出的第二个解决方案不会起作用,因为对
doSomething
的第二个调用实际上会调用在第一个调用中设置的行为,因此您将立即得到
IllegalArgumentException
。只有在使用“doXxx”系列存根方法时,“最后存根赢”行为才会生效。。。。。。所以在这个特殊的例子中,您希望第二个调用是
doReturn(“1”).when(myMock).doSomething(Matchers.eq(“1”)或者甚至只是
doReturn(“1”)。when(myMock)。doSomething(“1”)这对我不起作用。第二个
when()
调用抛出异常。
Here are those rare occasions when doReturn() comes handy:
<...some lines are skipped...>
Overriding a previous exception-stubbing:

hen(mock.foo()).thenThrow(new RuntimeException());
//Impossible: the exception-stubbed foo() method is called so RuntimeException is thrown.
when(mock.foo()).thenReturn("bar");

//You have to use doReturn() for stubbing:
doReturn("bar").when(mock).foo();