20

According to the documentation (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/junit/jupiter/EnabledIf.html#expression--) you can use the @EnabledIf annotation on a test class or test method like so:

@EnabledIf("${smoke.tests.enabled}")

or

@EnabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")

where the string is a placeholder for property available in the Spring Environment.

Suppose I have the following application.yml file:

smoke:
  tests:
    enabled: true
spring:
  profiles:
    active: test

And the following test class:

@EnabledIf(value = "#{${spring.profiles.active} == 'test'}", loadContext = true)
@SpringBootTest
public class SomeClassForTests {

    @Autowired SomeType autowiredType;

    @Test
    public void someTest() {
        // test logic...
    }

When I run the test I get the following error:

Test ignored.

org.junit.jupiter.engine.execution.ConditionEvaluationException: Failed to evaluate condition [org.springframework.test.context.junit.jupiter.EnabledIfCondition]: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'test' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?

    at org.junit.jupiter.engine.execution.ConditionEvaluator.evaluationException(ConditionEvaluator.java:91)
    at org.junit.jupiter.engine.execution.ConditionEvaluator.evaluate(ConditionEvaluator.java:80)
    at org.junit.jupiter.engine.execution.ConditionEvaluator.lambda$evaluate$2(ConditionEvaluator.java:66)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
    at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.tryAdvance(StreamSpliterators.java:302)
    at java.base/java.util.stream.Streams$ConcatSpliterator.tryAdvance(Streams.java:723)
    at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127)
    at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:543)
    at org.junit.jupiter.engine.execution.ConditionEvaluator.evaluate(ConditionEvaluator.java:68)
    at org.junit.jupiter.engine.descriptor.JupiterTestDescriptor.shouldBeSkipped(JupiterTestDescriptor.java:182)
    at org.junit.jupiter.engine.descriptor.JupiterTestDescriptor.shouldBeSkipped(JupiterTestDescriptor.java:54)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$checkWhetherSkipped$1(NodeTestTask.java:91)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.checkWhetherSkipped(NodeTestTask.java:91)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:71)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'test' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?
    at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:164)
    at org.springframework.test.context.junit.jupiter.AbstractExpressionEvaluatingCondition.evaluateExpression(AbstractExpressionEvaluatingCondition.java:164)
    at org.springframework.test.context.junit.jupiter.AbstractExpressionEvaluatingCondition.evaluateAnnotation(AbstractExpressionEvaluatingCondition.java:107)
    at org.springframework.test.context.junit.jupiter.EnabledIfCondition.evaluateExecutionCondition(EnabledIfCondition.java:46)
    at org.junit.jupiter.engine.execution.ConditionEvaluator.evaluate(ConditionEvaluator.java:75)
    ... 37 more
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'test' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?
    at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:217)
    at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104)
    at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:91)
    at org.springframework.expression.spel.ast.OpEQ.getValueInternal(OpEQ.java:42)
    at org.springframework.expression.spel.ast.OpEQ.getValueInternal(OpEQ.java:32)
    at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:109)
    at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:265)
    at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:161)
    ... 41 more

I am not too familiar with the Spring expression language. What exactly am I doing wrong?


Update 1:

Using the following two versions of the annotation:

@EnabledIf(value = "${spring.profiles.active == 'test'}", loadContext = true)

or

@EnabledIf(value = "#{spring.profiles.active == 'test'}", loadContext = true)

results in the following error: org.junit.jupiter.engine.execution.ConditionEvaluationException: Failed to evaluate condition [org.springframework.test.context.junit.jupiter.EnabledIfCondition]: @EnabledIf("${spring.profiles.active == 'test'}") on class SomeClassForTests must evaluate to "true" or "false", not "${spring.profiles.active == 'test'}"


Update 2:

The following:

@EnabledIf(value = "${spring.profiles.active} == 'test'", loadContext = true)

results in the following error:

org.junit.jupiter.engine.execution.ConditionEvaluationException: Failed to evaluate condition [org.springframework.test.context.junit.jupiter.EnabledIfCondition]: @EnabledIf("${spring.profiles.active} == 'test'") on class SomeClassForTests must evaluate to "true" or "false", not "test == 'test'"


Update 3: The answer of:

@EnabledIf(expression = "#{environment['spring.profiles.active'] == 'test'}", loadContext = true)

works when you have only one active profile. How would you do it when you have many, such as below:

smoke:
  tests:
    enabled: true
spring:
  profiles:
    active: 
    - test
    - someotherprofile
vab2048
  • 1,065
  • 8
  • 21
  • Please, checo How I got it in: https://stackoverflow.com/questions/54200138/system-getpropertyspring-profiles-active-always-getting-null-in-jpa-entity-l/71719806#71719806 – GtdDev Apr 02 '22 at 17:41
  • Please, check How I got it in: https://stackoverflow.com/questions/54200138/system-getpropertyspring-profiles-active-always-getting-null-in-jpa-entity-l/71719806#71719806 – GtdDev Apr 02 '22 at 17:43

3 Answers3

26

To check the exact value of a property from the Spring Environment, you should use the following approach.

@EnabledIf(expression = "#{environment['spring.profiles.active'] == 'test'}", loadContext = true)

To check which profiles are currently active in the Spring Environment, you should use the following approach.

@EnabledIf(expression = "#{environment.acceptsProfiles('test', 'someotherprofile')}", loadContext = true)
Sam Brannen
  • 29,611
  • 5
  • 104
  • 136
  • Thank you this works well when you have got only one active profile. But if you have many active profiles how would you go about with the spring expression to check the one you care about is within the active profile list? (I've updated the question with more details). – vab2048 Apr 18 '19 at 15:10
  • 1
    I've updated my answer to show how to check against multiple active profiles. – Sam Brannen Apr 21 '19 at 08:58
  • @SamBrannen We're using [Zonky](https://github.com/zonkyio/embedded-database-spring-test) to run integration tests on an embedded Postgres DB. This is configured by placing `@AutoConfigureEmbeddedDatabase` on the test class. With `loadContext=true`, Zonky is always initialized, even if the expression evaluates to false. This is problematic in contexts where Zonky cannot be launched due to missing process permissions (e.g. inside containers), which is precisely where we'd like to disable the test based on certain active profiles. Can you think of a way to solve this dilemma? – Hein Blöd Nov 03 '20 at 16:07
  • @SamBrannen I've tried t use `@EnabledIf`with the given expression on Class level without success. No matter how much or what profiles I've configured, the tests will be executed. I've tried `@DisabledIf` with the same outcome. I do not have a pure Junit5 setup, as some dependencies use Junit4 with `junit-vintage-engine`. Any idea how I can disable a test Class entirly based on spring profiles would be awesome! – zyexal Jan 20 '21 at 11:01
4

Try that with an extra apostrophe to wrap property when used in SpEL:

@EnabledIf(value = "#{'${spring.profiles.active}' == 'test'}", loadContext = true)

I worked for me (finally!) when I tried to use custom property

Krzysztof Skrzynecki
  • 2,345
  • 27
  • 39
1

Your expression should look like this:

@EnabledIf(value = "${spring.profiles.active == 'test'}", loadContext = true)
Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
  • Now the error is: `org.junit.jupiter.engine.execution.ConditionEvaluationException: Failed to evaluate condition [org.springframework.test.context.junit.jupiter.EnabledIfCondition]: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'spring' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?` – vab2048 Apr 16 '19 at 10:30
  • 1
    use $ sign instead of # – Maciej Kowalski Apr 16 '19 at 10:34
  • I have added updates to the original question with more annotations and their error messages. Unfortunately, using $ instead of # does not work either. – vab2048 Apr 16 '19 at 11:19
  • Check: https://stackoverflow.com/questions/54200138/system-getpropertyspring-profiles-active-always-getting-null-in-jpa-entity-l/71719806#71719806 – GtdDev Apr 02 '22 at 17:43