unit-testing - org.mockito.exceptions.misusing.WrongTypeOfReturnValue while stubbing a function from a "spy" object with mockito in groovy
问题描述
I'm having this issue which has taken enough time from me so I decided to ask the experts here. Some context.. I have a Jenkins shared library which with some groovy classes and I'm writing some unit tests using the JenkinsPipelineUnit framework. I'm using normal junit for testing so nothing special there. Basically I have a groovy class as following:
class MyClass {
// In reality, `run` is object from the final class WorkflowRun but in the tests, I pass here a dummy map with the important fields
def run
MyClass(def run) {
this.run = run
}
boolean somethingExists() {
// some code here that does some stuff on `run` and return a boolean
}
String doSomething() {
if(somethingExists()) {
// do something with it.
return "foo"
} else {
// do something else
return "bar"
}
}
}
The code above is simple enough and I am writing the following test for the doSomething()
function without having to mock all the internals of somethingExists()
.
@Test
void testDoSomething() {
Map run = [number: 1]
MyClass mc = spy(new MyClass(run))
// The problem is with the next line.
doReturn(true).when(mc).somethingExists()
assertTrue(mc.somethingExists())
assertEquals("foo", mc.doSomething())
}
Note that I cannot mock the WorkflowRun
class since it is a final class and honestly I don't care about it since I need to test the logic inside doSomething()
rather than what somethingExists()
does which is checking some Jenkins internals on the run
object. Therefore, I decided to "spy" on the object under test mc
and make it return a simple true
or false
when I call somethingExists()
to avoid too much mocking of the run object.
According to Mockito's documentation, when I use the spy function, I should use the stubbing format like I did doReturn(true).when(mc).somethingExists()
unlike the other format of when(mc.somethingExists()).thenReturn(true)
since this will actually call the real function on the class while attempting to stub it.
Error message:
When I call the doReturn(true).when(mc).somethingExists()
I get the following error
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Boolean cannot be returned by getMetaClass()
getMetaClass() should return MetaClass
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createPogoSite(CallSiteArray.java:140)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:158)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130)
at MyClassTest.testDoSomething(MyClassTest.groovy:37)
...
Note that I'm not running tests in parallel (actually while reproducing the issue, I was running only this test) and I'm following the stubbing rule suggested.
At first I thought it is because of the doReturn(true)
which is returning a primitive type instead of an object so I replaced it with doReturn(Boolean.FALSE)
but I still got the same error.
When I replace the line doReturn(true).when(mc).somethingExists()
with when(mc.somethingExists()).thenReturn(true)
then it fails because it is calling the real function mc.somethingExists()
which is expected in my opinion. On the other hand, when I replace the entire content of the somethingExists()
function with a simple return false
, surprisingly, the format doReturn(true).when(mc).somethingExists()
still failed however the other format when(mc.somethingExists()).thenReturn(true)
worked which I'm surprised because this format should not work for spy objects.
Any clues what I might be doing wrong? I have spent a lot of time trying to find the problem. Thanks in advance.
解决方案
推荐阅读
- django - Django REST Serializer 使用错误的模型进行序列化
- python - python文件写入程序运行时如何更新桌面上的文件大小
- javascript - 使用 d3.js 更新表数据
- c# - C#捕获从不在进程中的函数返回的异常?
- r - 如何设置仅在输入 3 时才显示集合向量的函数?
- javascript - 如果 URI 没有改变,例如在单页应用程序上,如何检测用户是否在新页面上?
- angular - Angular Kendo UI 全局访问
- php - 内连接循环通过
- git - 如何 git rebase 从另一个分支直接到 master 分支?
- javascript - 受控数字比例映射