能否使用Mockito模拟一个既是静态方法又是void方法的方法?

5

我在这里试图避免使用PowerMockito。我们有遗留代码,其中包含既是静态的又是void的方法,并且有需要模拟它们的测试。是否有一种方法可以做到这一点,或者改造遗留代码是唯一的方式?

class MySample {
       public static void sampleMethod(String argument){
                //do something
       }
}

如果我使用通用的MockStatic语法,它会要求我返回一些内容:
MockedStatic <MySample> sampleMock = Mockito.mockStatic( MySample.class );
sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)));

异常:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.mytests.Test.setMock(Test.java:35)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, which is not supported
 3. you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed

编辑:请注意,我希望模拟一个既是静态又是void的方法。

1
这个回答解决了你的问题吗?如何在没有PowerMock的情况下模拟静态方法 - chand mohd
谢谢回答,但是所引用的示例并不是针对void方法的。 - Kumar
@Slaw 在那个问题中被接受的答案期望我们有一个实例,但是这里要测试的方法是静态的。是否有一个既是静态又是void的方法的示例? - Kumar
2个回答

4

当被模拟的方法被调用时,您希望发生什么?

默认情况下,什么都不会发生。通过调用sampleMock.when(),您指示要从默认行为更改为其他内容。Mockito正在抱怨,因为您没有随后调用then___()来指定应该发生什么。

我可以想到几件您可能想要发生的事情:

1. 什么也不做

如前所述,这是默认行为,因此如果这是您想要的全部内容,则可以删除第二行,它应该能正常工作。但是,如果您真的需要一个when调用(例如用于参数捕获),则可以使用一个空的thenAnswer来结束该行:

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenAnswer(invocation -> null);

2. 调用真实方法

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenCallRealMethod();

3. 做些其他的事情

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenAnswer(invocation -> {
        // insert code to do something else here
        return null;
    });

4. 抛出异常

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenThrow(RuntimeException.class);

更新

如先前所述, 默认行为是什么都不做,但我了解到可以在创建模拟对象时通过提供一个Answer来指定替代默认行为。例如,如果要使默认行为调用真实的方法:

MockedStatic <MySample> sampleMock = Mockito.mockStatic( MySample.class, Mockito.CALLS_REAL_METHODS );

但要注意 - 正如Marc在此答案中所指出的那样,即使您覆盖了默认行为,真实的方法仍将被调用!这可能在未来得到修复;请参阅Marc的答案以获取一些很好的参考。


感谢您回答 @Kevin K,您可以看一下这个问题吗:https://dev59.com/M1IG5IYBdhLWcg3wlibO - Kumar
1
@Kumar 我了解到可以更改默认的模拟行为,并在此更新答案以通知您。我认为这也应该回答了您的另一个问题;如果您可以找出调用真实方法的默认行为,那么您可以为您想要模拟的特定方法添加“when”/“then”规则。 - Kevin K
2
@KevinK,你的更新是正确的,但是默认行为.callRealMethod()将始终触发静态方法,即使已经存根化。更多详细信息请参考我的回答https://dev59.com/M1IG5IYBdhLWcg3wlibO#63841319 - Marc
谢谢@Marc,这很有用。我也不知道Mockito.CALLS_REAL_METHODS,这很有用,我会更新我的示例。 - Kevin K

0
@RunWith(PowerMockRunner.class) 添加到你的类头部,可以防止抛出上述异常类型!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接