Issue
Background:
- project logic in Java 11 and Spring Boot 2.6.6
- some project features are conditionally available depending on specific application properties, some Spring components related with conditional features are also dependent using @ConditionalOnProperty annotation on component
- tests (also integration) are written in groovy and spock framework (ver. 2.1-groovy-3.0)
Question: Is it posible to make spock specification conditional on property from spring's application.properties?
Spock framework provides annotations which make test conditional. Most accurate seems to be @Requires for my case. (https://spockframework.org/spock/docs/2.1/all_in_one.html#_requires) Condition is based on PreconditionContext (https://spockframework.org/spock/docs/2.1/all_in_one.html#precondition_context).
Simplified Specificatiotion example (two working @Requires annotations left as example, but they do not check what is needed in my case):
import org.spockframework.runtime.extension.builtin.PreconditionContext
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.ContextConfiguration
import spock.lang.Requires
import spock.lang.Specification
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles('integration')
@ContextConfiguration(classes = TestSpringBootApplication)
//TODO: How to make this feature dependent of property from application.properties?
//@Requires(reason = 'Specification for AAA feature enabled', value = { isFeatureAAAEnabled() })
//@Requires(reason = 'Test run only on Linux', value = { PreconditionContext preconditionContext -> preconditionContext.os.windows })
class ConditionalSpec extends Specification {
//Some conditional components @Autowired
//feature methods
def "one plus one should equal two"() {
expect:
1 + 1 == 2
}
private static boolean isFeatureAAAEnabled() {
true
}
}
Solution
What do you want exactly, is it enough to just not run any tests but still start the spring context, or do you want to also avoid starting the spring context?
If it is the first one, then you can use instance
or shared
from the Precondition Context. If you enable shared field injection you should be able to do this.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles('integration')
@ContextConfiguration(classes = TestSpringBootApplication)
@EnableSharedInjection
@Requires(reason = 'Specification for AAA feature enabled', value = { shared.myValue == 'featureAAA' })
class ConditionalSpec extends Specification {
@Value('${value.from.file}')
@Shared
String myValue
//feature methods
def "one plus one should equal two"() {
expect:
1 + 1 == 2
}
}
If you can't use shared injection due to it's limitations, then you'll have to replace shared
by instance
in the condition.
If you want to avoid starting spring, then you'll have to write your own extension to figure out what the value from the application.properties
, and skip the spec yourself.
Answered By - Leonard Brünings
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)