Skip to content

Remove unnecessary annotations from Spring integration tests #2442

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1320,7 +1320,12 @@ enum class TypeReplacementMode {
}

sealed class SpringConfiguration(val fullDisplayName: String) {
class JavaConfiguration(val classBinaryName: String) : SpringConfiguration(classBinaryName)
abstract class JavaBasedConfiguration(open val configBinaryName: String) : SpringConfiguration(configBinaryName)

class JavaConfiguration(override val configBinaryName: String) : JavaBasedConfiguration(configBinaryName)

class SpringBootConfiguration(override val configBinaryName: String, val isUnique: Boolean): JavaBasedConfiguration(configBinaryName)

class XMLConfiguration(val absolutePath: String) : SpringConfiguration(absolutePath)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,26 @@ class CgSpringIntegrationTestClassConstructor(
)

private fun addNecessarySpringSpecificAnnotations() {
val isSpringBootTestAccessible = utContext.classLoader.tryLoadClass(springBootTestClassId.name) != null
if (isSpringBootTestAccessible) {
addAnnotation(springBootTestClassId, Class)
}

val (testFrameworkExtension, springExtension) = when (testFramework) {
Junit4 -> runWithClassId to springRunnerClassId
Junit5 -> extendWithClassId to springExtensionClassId
TestNg -> error("Spring extension is not implemented in TestNg")
else -> error("Trying to generate tests for Spring project with non-JVM framework")
}

addAnnotation(
classId = testFrameworkExtension,
argument = createGetClassExpression(springExtension, codegenLanguage),
target = Class,
)
// @SpringBootTest contains @ExtendWith(SpringExtension.class), no need to add it manually
if (!isSpringBootTestAccessible || testFrameworkExtension != extendWithClassId) {
addAnnotation(
classId = testFrameworkExtension,
argument = createGetClassExpression(springExtension, codegenLanguage),
target = Class,
)
}

if (utContext.classLoader.tryLoadClass(springBootTestContextBootstrapperClassId.name) != null)
// TODO in somewhat new versions of Spring Boot, @SpringBootTest
Expand All @@ -126,49 +134,44 @@ class CgSpringIntegrationTestClassConstructor(
target = Class,
)

if (utContext.classLoader.tryLoadClass(springBootTestClassId.name) != null)
addAnnotation(springBootTestClassId, Class)

// TODO avoid adding @ActiveProfiles(profiles = {"default"}) to reduce number of annotations
addAnnotation(
classId = activeProfilesClassId,
namedArguments =
listOf(
CgNamedAnnotationArgument(
name = "profiles",
value =
CgArrayAnnotationArgument(
springSettings.profiles.map { profile ->
profile.resolve()
}
val defaultProfileIsUsed = springSettings.profiles.singleOrNull() == "default"
if (!defaultProfileIsUsed) {
addAnnotation(
classId = activeProfilesClassId,
namedArguments = listOf(
CgNamedAnnotationArgument(
name = "profiles",
value = CgArrayAnnotationArgument(springSettings.profiles.map { profile -> profile.resolve() })
)
)
),
target = Class,
)
),
target = Class,
)
}

// TODO avoid adding @ContextConfiguration(classes = {$defaultBootConfigClass}) to reduce number of annotations
addAnnotation(
classId = contextConfigurationClassId,
namedArguments =
listOf(
CgNamedAnnotationArgument(
name = "classes",
value = CgArrayAnnotationArgument(
listOf(
createGetClassExpression(
// TODO:
// For now we support only JavaConfigurations in integration tests.
// Adapt for XMLConfigurations when supported.
ClassId((springSettings.configuration as JavaConfiguration).classBinaryName),
codegenLanguage
val configClass = springSettings.configuration as JavaBasedConfiguration
if (configClass is JavaConfiguration || configClass is SpringBootConfiguration && !configClass.isUnique) {
addAnnotation(
classId = contextConfigurationClassId,
namedArguments = listOf(
CgNamedAnnotationArgument(
name = "classes",
value = CgArrayAnnotationArgument(
listOf(
createGetClassExpression(
// TODO: we support only JavaConfigurations in integration tests.
// Adapt for XMLConfigurations when supported.
ClassId((springSettings.configuration as JavaConfiguration).configBinaryName),
codegenLanguage
)
)
)
)
)
),
target = Class,
)
),
target = Class,
)
}


addAnnotation(
classId = dirtiesContextClassId,
namedArguments = listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class SpringInstrumentationContext(
// so we expect JavaConfigurations only.
// After fix rewrite the following.
classLoader.loadClass(
(springSettings.configuration as? JavaConfiguration)?.classBinaryName
(springSettings.configuration as? JavaBasedConfiguration)?.configBinaryName
?: error("JavaConfiguration was expected, but ${springSettings.configuration.javaClass.name} was provided.")
)
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,10 @@ object UtTestsDialogProcessor {
is AbsentSpringSettings -> null
is PresentSpringSettings ->
when (val config = settings.configuration) {
is JavaConfiguration -> {
is JavaBasedConfiguration -> {
PsiClassHelper
.findClass(config.classBinaryName, project)
?: error("Cannot find configuration class ${config.classBinaryName}.")
.findClass(config.configBinaryName, project)
?: error("Cannot find configuration class ${config.configBinaryName}.")
}
// TODO: for XML config we also need to compile module containing,
// since it may reference classes from that module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,16 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
SpringConfiguration.XMLConfiguration(absolutePath)
} else {
val classBinaryName = javaConfigurationHelper.restoreFullName(shortConfigName)
SpringConfiguration.JavaConfiguration(classBinaryName)

val springBootConfigs = model.getSortedSpringBootApplicationClasses()
if (springBootConfigs.contains(classBinaryName)) {
SpringConfiguration.SpringBootConfiguration(
configBinaryName = classBinaryName,
isUnique = springBootConfigs.size == 1,
)
} else {
SpringConfiguration.JavaConfiguration(classBinaryName)
}
}

PresentSpringSettings(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import org.utbot.common.patchAnnotation
import org.utbot.framework.plugin.api.SpringConfiguration.*
import org.utbot.spring.api.ApplicationData
import org.utbot.spring.config.TestApplicationConfiguration
import org.utbot.spring.configurators.ApplicationConfigurationType
import java.nio.file.Path
import kotlin.io.path.Path

Expand All @@ -20,11 +19,11 @@ class SourceFinder(

fun findSources(): Array<Class<*>> =
when (val config = applicationData.springSettings.configuration) {
is JavaConfiguration -> {
is JavaBasedConfiguration -> {
logger.info { "Using java Spring configuration" }
arrayOf(
TestApplicationConfiguration::class.java,
classLoader.loadClass(config.classBinaryName)
classLoader.loadClass(config.configBinaryName)
)
}

Expand Down