Skip to content

Commit 918e80b

Browse files
committed
Call doNothing from mockito in tests for method calls returning void
1 parent 8321fc2 commit 918e80b

File tree

2 files changed

+44
-16
lines changed

2 files changed

+44
-16
lines changed

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/builtin/MockitoBuiltins.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ internal val ongoingStubbingClassId = BuiltinClassId(
2525
simpleName = "OngoingStubbing",
2626
)
2727

28+
internal val stubberClassId = BuiltinClassId(
29+
canonicalName = "org.mockito.stubbing.Stubber",
30+
simpleName = "Stubber"
31+
)
32+
2833
internal val answerClassId = BuiltinClassId(
2934
canonicalName = "org.mockito.stubbing.Answer",
3035
simpleName = "Answer",
@@ -73,6 +78,18 @@ internal val thenReturnMethodId = builtinMethodId(
7378
arguments = arrayOf(objectClassId)
7479
)
7580

81+
internal val doNothingMethodId = builtinStaticMethodId(
82+
classId = mockitoClassId,
83+
name = "doNothing",
84+
returnType = stubberClassId,
85+
)
86+
87+
internal val whenStubberMethodId = builtinMethodId(
88+
classId = stubberClassId,
89+
name = "when",
90+
returnType = objectClassId,
91+
)
92+
7693
// TODO: for this method and other static methods implement some utils that allow calling
7794
// TODO: these methods without explicit declaring class id specification, because right now such calls are too verbose
7895
internal val any = builtinStaticMethodId(

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ import org.utbot.framework.codegen.domain.builtin.anyLong
1313
import org.utbot.framework.codegen.domain.builtin.anyOfClass
1414
import org.utbot.framework.codegen.domain.builtin.anyShort
1515
import org.utbot.framework.codegen.domain.builtin.argumentMatchersClassId
16+
import org.utbot.framework.codegen.domain.builtin.doNothingMethodId
1617
import org.utbot.framework.codegen.domain.builtin.mockMethodId
1718
import org.utbot.framework.codegen.domain.builtin.mockedConstructionContextClassId
1819
import org.utbot.framework.codegen.domain.builtin.mockitoClassId
1920
import org.utbot.framework.codegen.domain.builtin.thenReturnMethodId
2021
import org.utbot.framework.codegen.domain.builtin.whenMethodId
22+
import org.utbot.framework.codegen.domain.builtin.whenStubberMethodId
2123
import org.utbot.framework.codegen.domain.context.CgContext
2224
import org.utbot.framework.codegen.domain.context.CgContextOwner
2325
import org.utbot.framework.codegen.domain.models.CgAnonymousFunction
@@ -178,28 +180,37 @@ private class MockitoMocker(context: CgContext) : ObjectMocker(context) {
178180
val mockObject = newVar(model.classId, baseName = baseName, isMock = true) { mock(modelClass) }
179181

180182
for ((executable, values) in model.mocks) {
181-
// void method
183+
val matchers = mockitoArgumentMatchersFor(executable)
184+
182185
if (executable.returnType == voidClassId) {
183-
// void methods on mocks do nothing by default
184-
continue
185-
}
186+
when (executable) {
187+
// All constructors are considered like void methods, but it is proposed to be changed to test constructors better.
188+
is ConstructorId -> continue
189+
// Sometimes void methods are called explicitly, e.g. annotated with @Mock fields in Spring test classes.
190+
// We would like to mark that this field is used and must not be removed from test class.
191+
// Without `doNothing` call Intellij Idea suggests removing this field as unused.
192+
is MethodId -> mockitoClassId[doNothingMethodId]()[whenStubberMethodId](mockObject)[executable](*matchers)
193+
else -> error("Only MethodId and ConstructorId was expected to appear in simple mocker but got $executable")
194+
}
195+
} else {
196+
when (executable) {
197+
is MethodId -> {
198+
if (executable.parameters.any { !it.isAccessibleFrom(testClassPackageName) }) {
199+
error("Cannot mock method $executable with not accessible parameters" )
200+
}
186201

187-
when (executable) {
188-
is MethodId -> {
189-
if (executable.parameters.any { !it.isAccessibleFrom(testClassPackageName) }) {
190-
error("Cannot mock method $executable with not accessible parameters" )
191-
}
202+
if (!executable.isAccessibleFrom(testClassPackageName)) {
203+
error("Cannot mock method $executable as it is not accessible from package $testClassPackageName")
204+
}
192205

193-
val matchers = mockitoArgumentMatchersFor(executable)
194-
if (!executable.isAccessibleFrom(testClassPackageName)) {
195-
error("Cannot mock method $executable as it is not accessible from package $testClassPackageName")
206+
val results = values.map { variableConstructor.getOrCreateVariable(it) }.toTypedArray()
207+
`when`(mockObject[executable](*matchers)).thenReturn(executable.returnType, *results)
196208
}
197-
198-
val results = values.map { variableConstructor.getOrCreateVariable(it) }.toTypedArray()
199-
`when`(mockObject[executable](*matchers)).thenReturn(executable.returnType, *results)
209+
else -> error("Only MethodId was expected to appear in simple mocker but got $executable")
200210
}
201-
else -> error("ConstructorId was not expected to appear in simple mocker but got $executable")
202211
}
212+
213+
203214
}
204215

205216
return mockObject

0 commit comments

Comments
 (0)