英文:
Is it possible to mock a method that is both static and void using Mockito?
问题
我试图避免在这里使用PowerMockito。我们有包含静态和void方法的遗留代码,还有需要模拟它们的测试。是否有方法可以做到这一点,或者重构遗留代码是唯一的方法?
如果我使用一般的MockStatic语法,它要求我返回某些内容:
MockedStatic<MySample> sampleMock = Mockito.mockStatic(MySample.class);
sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)));
异常信息:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
在这里检测到未完成的存根设置:
-> 在 com.mytests.Test.setMock(Test.java:35)
例如,可能缺少 thenReturn()。
正确存根设置的示例:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
提示:
1. 缺少 thenReturn()
2. 你正在尝试存根一个final方法,这是不受支持的
3. 在 before 'thenReturn' 指令完成之前,你正在存根另一个模拟的行为
注意:请注意,我想要模拟的方法既是静态的又是void的。
英文:
I'm trying to avoid using PowerMockito here. We have legacy code which contains methods that are both static and void and there are tests which need to mock them. Is there a way to do it or is refactoring legacy code the only way here?
class MySample {
public static void sampleMethod(String argument){
//do something
}
}
If I use the general MockStatic syntax, it asks me to return something:
MockedStatic <MySample> sampleMock = Mockito.mockStatic( MySample.class );
sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)));
Exception:
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
Edit: Please note that I'm looking to mock a method that is BOTH static and void.
答案1
得分: 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 -> {
// 插入要执行的其他代码
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的答案以获取一些良好的参考资料。
英文:
What do you want to happen when the mocked method gets called?
The default behavior is that nothing happens. By calling sampleMock.when()
, you indicated that you wanted to change from the default behavior to something else. Mockito is complaining because you didn't then follow that up with a call to then___()
to specify what should happen instead.
There are a few different things I can think of that you might want to have happen:
1. Do nothing
As previously stated, this is the default behavior, so if this is all you want, you can just remove the second line and it should work. But, if you really need to have a when
call (e.g. for argument capture), you can instead finish off the line with an empty thenAnswer
:
sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
.thenAnswer(invocation -> null);
2. Call the real method
sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
.thenCallRealMethod();
3. Do something else
sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
.thenAnswer(invocation -> {
// insert code to do something else here
return null;
});
4. Throw an exception
sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
.thenThrow(RuntimeException.class);
Update
As previously mentioned, the default behavior is to do nothing, but I learned it's also possible to specify an alternate default behavior by providing an Answer
when creating the mock. For example, to have the default behavior call the real method instead:
MockedStatic <MySample> sampleMock = Mockito.mockStatic( MySample.class, Mockito.CALLS_REAL_METHODS );
But beware - as noted by Marc in this answer, the real method will still be called even if you override the default behavior! This may be fixed in the future; see Marc's answer for some good references
答案2
得分: 0
将 @RunWith(PowerMockRunner.class)
添加到你的类头部将阻止抛出前面提到的异常类型!
英文:
Adding @RunWith(PowerMockRunner.class)
to your class header will prevent the throw of the aforementioned exception type!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论