spockframework / spockframework/spock
'as boolean' coercion on null/absent property evaluates to null in assertion blocks (Groovy 5)
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 3.6k
- Forks
- 483
- PR merge metrics
- No merged PRs in 30d
Description
Describe the bug
In Spock then: or expect: blocks, using the as boolean operator on a null value or missing map entry—even when explicitly parenthesized—fails to coerce the value to false.
In standard Groovy 5, (null as boolean) == false evaluates to true. However, inside a Spock assertion block in spock-2.4-groovy-5.0, the AST rewriter bypasses the boolean coercion step, leaving the expression as null == false and causing the condition to fail.
To Reproduce
Run the following Specification with spock-core:2.4-groovy-5.0 and groovy:5.0.x:
import spock.lang.Specification
class AsBooleanGroovy5BugSpec extends Specification {
def "as boolean cast should coerce null map entry to false in assertion block"() {
given:
def result = [error: true]
expect:
(result.success as boolean) == false
}
}
Expected behavior
(result.success as boolean) should evaluate to false via Groovy Truth coercion, making false == false pass.
Actual behavior
The test fails with a ConditionNotSatisfiedError. Spock evaluates the left operand as null instead of false:
Condition not satisfied:
(result.success as boolean) == false
| | |
| null false
[error:true]
``
Java version
- Spock Version: 2.4-groovy-5.0
- Groovy Version: 5.0.x
- JDK Version: 17+
Buildtool version
------------------------------------------------------------
Gradle 9.6.0
------------------------------------------------------------
Build time: 2026-06-18 23:19:03 UTC
Revision: 3f750f03d77e42327c5f9fcb9992110088330a32
Kotlin: 2.3.21
Groovy: 4.0.32
Ant: Apache Ant(TM) version 1.10.17 compiled on April 6 2026
Launcher JVM: 25.0.4 (BellSoft 25.0.4+9-LTS)
Daemon JVM: /home/x/.sdkman/candidates/java/25.0.4-librca (no Daemon JVM specified, using current Java home)
OS: Linux 6.17.0-1032-oem amd64
What operating system are you using
Linux
Dependencies
org.spockframework:spock-core:2.4-groovy-5.0
+--- org.apache.grails:grails-base-bom:8.0.0-SNAPSHOT
| \--- org.apache.grails:grails-bom:8.0.0-SNAPSHOT
| +--- testCompileClasspath (requested org.apache.grails:grails-bom:8.0.0-M5)
| +--- edu.berkeley.calnet.grails.plugins:registry-settings:3.0.0-SNAPSHOT
| | \--- testCompileClasspath
| +--- edu.berkeley.calnet.grails.plugins:calnet-ui:3.0.0-SNAPSHOT (requested org.apache.grails:grails-bom:8.0.0-M5)
| | \--- testCompileClasspath
| +--- edu.berkeley.calnet.grails.plugins:ucb-spring-security-cas-ldap:5.0.0-SNAPSHOT
| | \--- testCompileClasspath
| +--- edu.berkeley.calnet.grails.plugins:registry-rest-client:3.0.0-SNAPSHOT (requested org.apache.grails:grails-bom:8.0.0-M5)
| | \--- testCompileClasspath
| \--- org.apache.grails:grails-base-bom:8.0.0-SNAPSHOT (*)
+--- org.apache.grails:grails-bom:8.0.0-SNAPSHOT (*)
+--- org.apache.grails:grails-testing-support-views-gson:8.0.0-SNAPSHOT
| +--- testCompileClasspath (requested org.apache.grails:grails-testing-support-views-gson)
| \--- org.apache.grails:grails-base-bom:8.0.0-SNAPSHOT (*)
+--- org.apache.grails.testing:grails-test-core:8.0.0-SNAPSHOT
| +--- org.apache.grails:grails-base-bom:8.0.0-SNAPSHOT (*)
| \--- org.apache.grails.testing:grails-testing-support-core:8.0.0-SNAPSHOT
| +--- org.apache.grails:grails-base-bom:8.0.0-SNAPSHOT (*)
| \--- org.apache.grails:grails-testing-support-web:8.0.0-SNAPSHOT
| +--- testCompileClasspath (requested org.apache.grails:grails-testing-support-web)
| \--- org.apache.grails:grails-base-bom:8.0.0-SNAPSHOT (*)
\--- org.spockframework:spock-bom:2.4-groovy-5.0
+--- org.apache.grails:grails-base-bom:8.0.0-SNAPSHOT (*)
+--- org.apache.grails:grails-bom:8.0.0-SNAPSHOT (*)
\--- org.spockframework:spock-core:2.4-groovy-5.0 (*)
org.spockframework:spock-core -> 2.4-groovy-5.0
\--- testCompileClasspath
Additional context
Work-around
Because as boolean is stripped/ignored by the condition rewriter under Groovy 5, use explicit null checking or defaulting instead:
- Elvis Operator:
(result.success ?: false) == false - Map Defaulting:
result.get('success', false) == false - Groovy Truth Assertion:
!result.success
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the supplied AsBooleanGroovy5BugSpec reproduction with Spock 2.4-groovy-5.0 and Groovy 5. Trace the assertion-block AST rewriter to determine where the parenthesized as boolean expression is bypassed; done means the reproduction passes and null or absent map values coerce to false.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- groovy
- Domain
- testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100