spockframework / spockframework/spock
Interactions in when blocks are not preserved if the then block contains an interaction
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
Interactions in a when: block are not active after the following then: block, if the then: block contains an interactions,
although the documentation states:
"Interactions declared outside a then: block are active from their declaration until the end of the
containing feature method."
The two features below describe the problem
"When block interaction still active after when block without verification"
"When block interactions are only active during the when block, if verification present"
The single verification line 1 * m.start() in the then: block, changes the behavior of the m.isStarted() method for the rest of the feature execution.
Internals:
If there is a interaction in the then: block, there is a second InteractionScope in the MockController and the interaction in the when: will be added to the top InteractionScope (the second scope from the then:), which will be deactivated by the leaveScope() of the then:. This will drop the interaction from the when: block.
So it does not reflect the behavior stated in the documentation.
Also see the discussion in #1728.
To Reproduce
def "When block interaction still active after when block without verification"() {
given:
def m = Mock(Engine)
when:
m.isStarted() >> true
def result = m.isStarted()
m.start()
then:
m.isStarted()
result
when: "Here the isStarted() still reflect the when block above"
result = m.isStarted()
then:
m.isStarted()
result
}
def "When block interactions are only active during the when block, if verification present"() {
given:
def m = Mock(Engine)
when:
m.isStarted() >> true
def result = m.isStarted()
m.start()
then:
//If you remove the next line the behavior of isStarted() is different
1 * m.start()
!m.isStarted()
result
when: "Now the isStarted() does not reflect the when block"
result = m.isStarted()
then:
!m.isStarted()
!result
}
static class Engine {
private boolean started
boolean isStarted() { return started }
void start() { started = true }
void stop() { started = false }
}
Expected behavior
The interactions in when block shall be preserved up until the end of the feature method.
Actual behavior
The when: block interactions are dropped after the when: block.
So I would expected that the m.isStarted() >> true holds up until the end of the feature, and should not be affected by the 1 * m.start() in the then: block.
Java version
17.0.8
Buildtool version
Gradle 8.1
Build time: 2023-04-12 12:07:45 UTC
Revision: 40ba32cde9d6daf2b92c39376d2758909dd6b813
Kotlin: 1.8.10
Groovy: 3.0.15
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 17.0.8 (Amazon.com Inc. 17.0.8+7-LTS)
OS: Windows 10 10.0 amd64
What operating system are you using
Windows
Dependencies
Spock-master
Additional context
No response
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 with the two reproduction feature methods in issue #1759 and trace MockController's InteractionScope handling across when and then blocks. Inspect how leaveScope() deactivates scopes, then add or run regression coverage for interactions declared in when blocks. Done means those interactions remain active through the containing feature method even when a then block contains an interaction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- groovy, java
- Domain
- testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100