Skip to content

Commit 2535296

Browse files
Render setUp and tearDown for Spring testing (#1835)
1 parent 369de9d commit 2535296

File tree

12 files changed

+223
-21
lines changed

12 files changed

+223
-21
lines changed

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

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ abstract class TestFramework(
182182
abstract val testAnnotation: String
183183
abstract val testAnnotationId: ClassId
184184
abstract val testAnnotationFqn: String
185+
abstract val beforeMethod: String
186+
abstract val beforeMethodId: ClassId
187+
abstract val beforeMethodFqn: String
188+
abstract val afterMethod: String
189+
abstract val afterMethodId: ClassId
190+
abstract val afterMethodFqn: String
185191
abstract val parameterizedTestAnnotation: String
186192
abstract val parameterizedTestAnnotationId: ClassId
187193
abstract val parameterizedTestAnnotationFqn: String
@@ -261,8 +267,27 @@ abstract class TestFramework(
261267

262268
object TestNg : TestFramework(id = "TestNG",displayName = "TestNG") {
263269
override val mainPackage: String = TEST_NG_PACKAGE
270+
264271
override val testAnnotation: String = "@$mainPackage.Test"
265272
override val testAnnotationFqn: String = "$mainPackage.Test"
273+
override val testAnnotationId: ClassId = BuiltinClassId(
274+
canonicalName = "$mainPackage.annotations.Test",
275+
simpleName = "Test"
276+
)
277+
278+
override val beforeMethod = "@${mainPackage}.BeforeMethod"
279+
override val beforeMethodFqn = "${mainPackage}.BeforeMethod"
280+
override val beforeMethodId = BuiltinClassId(
281+
canonicalName = "${mainPackage}.BeforeMethod",
282+
simpleName = "BeforeMethod"
283+
)
284+
285+
override val afterMethod = "@${mainPackage}.AfterMethod"
286+
override val afterMethodFqn = "${mainPackage}.AfterMethod"
287+
override val afterMethodId = BuiltinClassId(
288+
canonicalName = "${mainPackage}.AfterMethod",
289+
simpleName = "AfterMethod"
290+
)
266291

267292
override val parameterizedTestAnnotation: String = "@$mainPackage.Test"
268293
override val parameterizedTestAnnotationFqn: String = "@$mainPackage.Test"
@@ -301,11 +326,6 @@ object TestNg : TestFramework(id = "TestNG",displayName = "TestNG") {
301326
)
302327
)
303328

304-
override val testAnnotationId: ClassId = BuiltinClassId(
305-
canonicalName = "$mainPackage.annotations.Test",
306-
simpleName = "Test"
307-
)
308-
309329
override val parameterizedTestAnnotationId: ClassId = BuiltinClassId(
310330
canonicalName = "$mainPackage.annotations.Test",
311331
simpleName = "Test",
@@ -370,8 +390,27 @@ object Junit4 : TestFramework(id = "JUnit4",displayName = "JUnit 4") {
370390
get() = error("Parametrized tests are not supported for JUnit 4")
371391

372392
override val mainPackage: String = JUNIT4_PACKAGE
393+
373394
override val testAnnotation = "@$mainPackage.Test"
374395
override val testAnnotationFqn: String = "$mainPackage.Test"
396+
override val testAnnotationId = BuiltinClassId(
397+
canonicalName = "$mainPackage.Test",
398+
simpleName = "Test"
399+
)
400+
401+
override val beforeMethod = "@$mainPackage.Before"
402+
override val beforeMethodFqn = "$mainPackage.Before"
403+
override val beforeMethodId = BuiltinClassId(
404+
canonicalName = "$mainPackage.Before",
405+
simpleName = "Before"
406+
)
407+
408+
override val afterMethod = "@$mainPackage.After"
409+
override val afterMethodFqn = "$mainPackage.After"
410+
override val afterMethodId = BuiltinClassId(
411+
canonicalName = "$mainPackage.After",
412+
simpleName = "After"
413+
)
375414

376415
override val parameterizedTestAnnotation
377416
get() = parametrizedTestsNotSupportedError
@@ -382,11 +421,6 @@ object Junit4 : TestFramework(id = "JUnit4",displayName = "JUnit 4") {
382421
override val methodSourceAnnotationFqn
383422
get() = parametrizedTestsNotSupportedError
384423

385-
override val testAnnotationId = BuiltinClassId(
386-
canonicalName = "$JUNIT4_PACKAGE.Test",
387-
simpleName = "Test"
388-
)
389-
390424
override val parameterizedTestAnnotationId = voidClassId
391425
override val methodSourceAnnotationId = voidClassId
392426

@@ -431,8 +465,28 @@ object Junit4 : TestFramework(id = "JUnit4",displayName = "JUnit 4") {
431465

432466
object Junit5 : TestFramework(id = "JUnit5", displayName = "JUnit 5") {
433467
override val mainPackage: String = JUNIT5_PACKAGE
468+
434469
override val testAnnotation = "@$mainPackage.Test"
435470
override val testAnnotationFqn: String = "$mainPackage.Test"
471+
override val testAnnotationId = BuiltinClassId(
472+
canonicalName = "$JUNIT5_PACKAGE.Test",
473+
simpleName = "Test"
474+
)
475+
476+
override val beforeMethod = "@${mainPackage}.BeforeEach"
477+
override val beforeMethodFqn = "${mainPackage}.BeforeEach"
478+
override val beforeMethodId = BuiltinClassId(
479+
canonicalName = "${mainPackage}.BeforeEach",
480+
simpleName = "BeforeEach"
481+
)
482+
483+
override val afterMethod = "@${mainPackage}.AfterEach"
484+
override val afterMethodFqn = "${mainPackage}.AfterEach"
485+
override val afterMethodId = BuiltinClassId(
486+
canonicalName = "${mainPackage}.AfterEach",
487+
simpleName = "AfterEach"
488+
)
489+
436490
override val parameterizedTestAnnotation = "$JUNIT5_PARAMETERIZED_PACKAGE.ParameterizedTest"
437491
override val parameterizedTestAnnotationFqn: String = "$JUNIT5_PARAMETERIZED_PACKAGE.ParameterizedTest"
438492
override val methodSourceAnnotation: String = "$JUNIT5_PARAMETERIZED_PACKAGE.provider.MethodSource"
@@ -470,11 +524,6 @@ object Junit5 : TestFramework(id = "JUnit5", displayName = "JUnit 5") {
470524
simpleName = "Nested"
471525
)
472526

473-
override val testAnnotationId = BuiltinClassId(
474-
canonicalName = "$JUNIT5_PACKAGE.Test",
475-
simpleName = "Test"
476-
)
477-
478527
override val parameterizedTestAnnotationId = BuiltinClassId(
479528
canonicalName = "$JUNIT5_PARAMETERIZED_PACKAGE.ParameterizedTest",
480529
simpleName = "ParameterizedTest"

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.utbot.framework.codegen.domain.builtin
22

3+
import org.mockito.MockitoAnnotations
34
import org.utbot.framework.codegen.domain.MockitoStaticMocking
45
import org.utbot.framework.codegen.domain.models.CgClassId
56
import org.utbot.framework.codegen.renderer.utilMethodTextById
@@ -303,11 +304,18 @@ internal val utKotlinUtilsClassId: ClassId
303304
/**
304305
* [MethodId] for [AutoCloseable.close].
305306
*/
307+
val openMocksMethodId = MethodId(
308+
classId = MockitoAnnotations::class.id,
309+
name = "openMocks",
310+
returnType = AutoCloseable::class.java.id,
311+
parameters = listOf(objectClassId),
312+
)
313+
306314
val closeMethodId = MethodId(
307315
classId = AutoCloseable::class.java.id,
308316
name = "close",
309317
returnType = voidClassId,
310-
parameters = emptyList()
318+
parameters = emptyList(),
311319
)
312320

313321
val mocksAutoCloseable: Set<ClassId> = setOf(

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/CgElement.kt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ interface CgElement {
4444
is CgMethodsCluster -> visit(element)
4545
is CgAuxiliaryClass -> visit(element)
4646
is CgUtilMethod -> visit(element)
47+
is CgFrameworkUtilMethod -> visit(element)
4748
is CgTestMethod -> visit(element)
4849
is CgErrorTestMethod -> visit(element)
4950
is CgParameterizedTestDataProviderMethod -> visit(element)
@@ -282,13 +283,25 @@ class CgTestMethod(
282283
val type: CgTestMethodType,
283284
override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList()),
284285
override val requiredFields: List<CgParameterDeclaration> = emptyList(),
285-
) : CgMethod(false)
286+
) : CgMethod(isStatic = false)
287+
288+
class CgFrameworkUtilMethod(
289+
override val name: String,
290+
override val statements: List<CgStatement>,
291+
override val exceptions: Set<ClassId>,
292+
override val annotations: List<CgAnnotation>,
293+
) : CgMethod(isStatic = false) {
294+
override val returnType: ClassId = voidClassId
295+
override val parameters: List<CgParameterDeclaration> = emptyList()
296+
override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList())
297+
override val requiredFields: List<CgParameterDeclaration> = emptyList()
298+
}
286299

287300
class CgErrorTestMethod(
288301
override val name: String,
289302
override val statements: List<CgStatement>,
290303
override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList())
291-
) : CgMethod(false) {
304+
) : CgMethod(isStatic = false) {
292305
override val exceptions: Set<ClassId> = emptySet()
293306
override val returnType: ClassId = voidClassId
294307
override val parameters: List<CgParameterDeclaration> = emptyList()

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgAbstractRenderer.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import org.utbot.framework.codegen.domain.models.CgExpression
4343
import org.utbot.framework.codegen.domain.models.CgFieldAccess
4444
import org.utbot.framework.codegen.domain.models.CgForEachLoop
4545
import org.utbot.framework.codegen.domain.models.CgForLoop
46+
import org.utbot.framework.codegen.domain.models.CgFrameworkUtilMethod
4647
import org.utbot.framework.codegen.domain.models.CgGreaterThan
4748
import org.utbot.framework.codegen.domain.models.CgIfStatement
4849
import org.utbot.framework.codegen.domain.models.CgIncrement
@@ -236,6 +237,14 @@ abstract class CgAbstractRenderer(
236237
visit(element.statements, printNextLine = true)
237238
}
238239

240+
override fun visit(element: CgFrameworkUtilMethod) {
241+
for (annotation in element.annotations) {
242+
annotation.accept(this)
243+
}
244+
renderMethodSignature(element)
245+
visit(element as CgMethod)
246+
}
247+
239248
override fun visit(element: CgTestMethod) {
240249
renderMethodDocumentation(element)
241250
for (annotation in element.annotations) {
@@ -751,6 +760,7 @@ abstract class CgAbstractRenderer(
751760
protected abstract fun renderMethodSignature(element: CgTestMethod)
752761
protected abstract fun renderMethodSignature(element: CgErrorTestMethod)
753762
protected abstract fun renderMethodSignature(element: CgParameterizedTestDataProviderMethod)
763+
protected abstract fun renderMethodSignature(element: CgFrameworkUtilMethod)
754764

755765
protected abstract fun renderForLoopVarControl(element: CgForLoop)
756766

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgJavaRenderer.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import org.utbot.framework.codegen.domain.models.CgSwitchCaseLabel
3333
import org.utbot.framework.codegen.domain.models.CgClass
3434
import org.utbot.framework.codegen.domain.models.CgClassBody
3535
import org.utbot.framework.codegen.domain.models.CgFormattedString
36+
import org.utbot.framework.codegen.domain.models.CgFrameworkUtilMethod
3637
import org.utbot.framework.codegen.domain.models.CgLiteral
3738
import org.utbot.framework.codegen.domain.models.CgTestMethod
3839
import org.utbot.framework.codegen.domain.models.CgTypeCast
@@ -254,6 +255,15 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C
254255
renderExceptions(element)
255256
}
256257

258+
override fun renderMethodSignature(element: CgFrameworkUtilMethod) {
259+
// framework util methods always have void return type
260+
print("public void ")
261+
print(element.name)
262+
print("()")
263+
264+
renderExceptions(element)
265+
}
266+
257267
override fun visit(element: CgInnerBlock) {
258268
println("{")
259269
withIndent {

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgKotlinRenderer.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import org.utbot.framework.codegen.domain.models.CgSwitchCaseLabel
3939
import org.utbot.framework.codegen.domain.models.CgClass
4040
import org.utbot.framework.codegen.domain.models.CgClassBody
4141
import org.utbot.framework.codegen.domain.models.CgFormattedString
42+
import org.utbot.framework.codegen.domain.models.CgFrameworkUtilMethod
4243
import org.utbot.framework.codegen.domain.models.CgLiteral
4344
import org.utbot.framework.codegen.domain.models.CgTestMethod
4445
import org.utbot.framework.codegen.domain.models.CgTypeCast
@@ -415,6 +416,14 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter =
415416
println("fun ${element.name}(): $returnType")
416417
}
417418

419+
override fun renderMethodSignature(element: CgFrameworkUtilMethod) {
420+
print("fun ")
421+
// TODO: resolve $ in name as in [CgTestMethod]
422+
print(element.name)
423+
print("()")
424+
renderMethodReturnType(element)
425+
}
426+
418427
private fun renderMethodReturnType(method: CgMethod) {
419428
if (method.returnType != voidClassId) {
420429
print(": ")

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgVisitor.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ import org.utbot.framework.codegen.domain.models.CgClass
7777
import org.utbot.framework.codegen.domain.models.CgClassBody
7878
import org.utbot.framework.codegen.domain.models.CgDocRegularLineStmt
7979
import org.utbot.framework.codegen.domain.models.CgFormattedString
80+
import org.utbot.framework.codegen.domain.models.CgFrameworkUtilMethod
8081
import org.utbot.framework.codegen.domain.models.CgNestedClassesRegion
8182
import org.utbot.framework.codegen.domain.models.CgTestMethod
8283
import org.utbot.framework.codegen.domain.models.CgTestMethodCluster
@@ -113,6 +114,7 @@ interface CgVisitor<R> {
113114
fun visit(element: CgTestMethod): R
114115
fun visit(element: CgErrorTestMethod): R
115116
fun visit(element: CgParameterizedTestDataProviderMethod): R
117+
fun visit(element: CgFrameworkUtilMethod): R
116118

117119
// Annotations
118120
fun visit(element: CgCommentedAnnotation): R

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,42 @@
11
package org.utbot.framework.codegen.tree
22

33
import org.utbot.framework.codegen.domain.builtin.TestClassUtilMethodProvider
4+
import org.utbot.framework.codegen.domain.builtin.closeMethodId
5+
import org.utbot.framework.codegen.domain.builtin.openMocksMethodId
46
import org.utbot.framework.codegen.domain.context.CgContext
7+
import org.utbot.framework.codegen.domain.models.CgAssignment
58
import org.utbot.framework.codegen.domain.models.CgClassBody
9+
import org.utbot.framework.codegen.domain.models.CgDeclaration
10+
import org.utbot.framework.codegen.domain.models.CgFrameworkUtilMethod
611
import org.utbot.framework.codegen.domain.models.CgMethod
12+
import org.utbot.framework.codegen.domain.models.CgMethodCall
713
import org.utbot.framework.codegen.domain.models.CgMethodTestSet
814
import org.utbot.framework.codegen.domain.models.CgMethodsCluster
915
import org.utbot.framework.codegen.domain.models.CgRegion
16+
import org.utbot.framework.codegen.domain.models.CgSimpleRegion
17+
import org.utbot.framework.codegen.domain.models.CgStatementExecutableCall
1018
import org.utbot.framework.codegen.domain.models.CgStaticsRegion
19+
import org.utbot.framework.codegen.domain.models.CgVariable
1120
import org.utbot.framework.codegen.domain.models.SpringTestClassModel
21+
import org.utbot.framework.plugin.api.UtCompositeModel
22+
import org.utbot.framework.plugin.api.util.id
23+
import org.utbot.framework.plugin.api.util.objectClassId
1224

1325
class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConstructor<SpringTestClassModel>(context) {
1426

27+
private val variableConstructor: CgVariableConstructor = CgComponents.getVariableConstructorBy(context)
28+
private val statementConstructor: CgStatementConstructor = CgComponents.getStatementConstructorBy(context)
29+
1530
override fun constructTestClassBody(testClassModel: SpringTestClassModel): CgClassBody {
1631
return buildClassBody(currentTestClass) {
1732

1833
// TODO: support inner classes here
1934

2035
// TODO: create class variables with Mock/InjectMock annotations using testClassModel
21-
fields += mutableListOf()
2236

23-
// TODO: create beforeEach/ afterEach methods
24-
// Requires new implementation of CgMethod for test framework builtins
37+
val (closeableField, closeableMethods) = constructMockitoCloseables()
38+
fields += closeableField
39+
methodRegions += closeableMethods
2540

2641
for (testSet in testClassModel.methodTestSets) {
2742
updateCurrentExecutable(testSet.executableId)
@@ -61,4 +76,57 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst
6176

6277
return if (regions.any()) regions else null
6378
}
79+
80+
private fun constructMockitoCloseables(): Pair<CgDeclaration, CgMethodsCluster> {
81+
val mockitoCloseableVarName = "mockitoCloseable"
82+
val mockitoCloseableVarType = java.lang.AutoCloseable::class.id
83+
84+
val mockitoCloseableModel = UtCompositeModel(
85+
id = null,
86+
classId = mockitoCloseableVarType,
87+
isMock = false,
88+
)
89+
90+
val mockitoCloseableVariable =
91+
variableConstructor.getOrCreateVariable(mockitoCloseableModel, mockitoCloseableVarName)
92+
val mockitoCloseableField = CgDeclaration(mockitoCloseableVarType, mockitoCloseableVarName, initializer = null)
93+
94+
importIfNeeded(openMocksMethodId)
95+
96+
val openMocksCall = CgMethodCall(
97+
caller = null,
98+
executableId = openMocksMethodId,
99+
//TODO: this is a hack of this
100+
arguments = listOf(CgVariable("this", objectClassId))
101+
)
102+
103+
val closeCall = CgMethodCall(
104+
caller = mockitoCloseableVariable,
105+
executableId = closeMethodId,
106+
arguments = emptyList(),
107+
)
108+
109+
val openMocksStatement = CgAssignment(mockitoCloseableVariable, openMocksCall)
110+
val beforeMethod = CgFrameworkUtilMethod(
111+
name = "setUp",
112+
statements = listOf(openMocksStatement),
113+
exceptions = emptySet(),
114+
annotations = listOf(statementConstructor.annotation(context.testFramework.beforeMethodId)),
115+
)
116+
117+
val closeStatement = CgStatementExecutableCall(closeCall)
118+
val afterMethod = CgFrameworkUtilMethod(
119+
name = "tearDown",
120+
statements = listOf(closeStatement),
121+
exceptions = setOf(java.lang.Exception::class.id),
122+
annotations = listOf(statementConstructor.annotation(context.testFramework.afterMethodId)),
123+
)
124+
125+
val methodCluster = CgMethodsCluster(
126+
"Test run utility methods",
127+
listOf(CgSimpleRegion("Mocking utils", listOf(beforeMethod, afterMethod)))
128+
)
129+
130+
return mockitoCloseableField to methodCluster
131+
}
64132
}

0 commit comments

Comments
 (0)