-
Notifications
You must be signed in to change notification settings - Fork 470
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
Interactions in when blocks are not preserved if the then block contains an interaction #1759
Comments
Interactions in a when: block were not active after the following then: block, if the then: block contained an interactions. Now the SpecRewriter inserts a "freezeScope" after the moved interactions from then blocks. This let the MockController skip the scope and use the outer scope for the interactions from the when block code. This fixes spockframework#1759
The question is, whether it makes actually sense to define interactions in the |
@Vampire for a clean test you are right, but I guess that there are tests out there which are not that clean. Also you can't have multiple For me the fix shall make the behavior more alligned with the documentation and remove the current surprise, when you add a single unrelated interaction in the I would find the change to forbid interactions in |
Well, we break existing tests either way. def foo() {
given:
def mock = Mock(Object)
when:
mock.hashCode() >> 1
mock.toString()
def result = mock.hashCode()
then:
1 * mock.toString()
result == 1
when:
mock.hashCode() >> 2
mock.toString()
result = mock.hashCode()
then:
1 * mock.toString()
result == 2 // <=== fails with the suggested changes, worked before
} then your suggestion would make the test suddenly fail as the
Not considering #1762 as imho the outcome for it is totally unclear right now, whether there will be any changes done at all and if so, which, Given that, it is currently already not possible to change the return value using an interaction. This will fail as in the second def foo() {
given:
def mock = Mock(Object)
when:
mock.hashCode() >> 1
then:
mock.hashCode() == 1
when:
mock.hashCode() >> 2
then:
mock.hashCode() == 2 // <=== fails
}
(Yes, same quote again) def foo() {
given:
def mockedHashCode
def mock = Mock(Object) {
hashCode() >> { mockedHashCode }
}
when:
mockedHashCode = 1
def result = mock.hashCode()
then:
result == 1
when:
mockedHashCode = 2
result = mock.hashCode()
then:
result == 2
}
I fully agree that the current behaviour does not match the documentation.
As I demonstrated, both changes are invasive and breaking changes. I'm also curious what @leonard84 thinks about the topic. |
I think we should fix the documentation instead of changing Spock's behavior. I touched on the why this happens in my answer here #1762 (comment), TL;DR |
@leonard84 @Vampire I am still not 100% convinced, because it is not consistent. If the |
As described above, I fully agree with @AndreasTu that the current behavior is very strange and unintuitive. I just don't agree with the suggested solution, but suggest to instead disallow defining interactions in Making the |
I think simply we can't simply forbid adding interactions in import spock.lang.*
class ASpec extends Specification {
def "hello world"() {
given:
List a = Mock()
when:
def result = a.get(0).size()
then:
1 * a.get(_) >> {
Stub(List) {
size() >> 42
}
}
result == 42
}
} We could disallow the writing of interaction instructions in the
We could make it always open an interactions scope, even though there are no interactions defined in the |
import spock.lang.*
class ASpec extends Specification {
def "hello world"() {
given:
List a = Mock()
List b = Stub {
size() >> 42
}
when:
def result = a.get(0).size()
then:
1 * a.get(_) >> b
result == 42
}
} :-) So yeah, forbidding is probably not a good solution :-( |
Describe the bug
Interactions in a
when:
block are not active after the followingthen:
block, if thethen:
block contains an interactions,although the documentation states:
"Interactions declared outside a
then:
block are active from their declaration until the end of thecontaining 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 them.isStarted()
method for the rest of the feature execution.Internals:
If there is a interaction in the
then:
block, there is a secondInteractionScope
in theMockController
and the interaction in thewhen:
will be added to the topInteractionScope
(the second scope from the then:), which will be deactivated by theleaveScope()
of thethen:
. This will drop the interaction from thewhen:
block.So it does not reflect the behavior stated in the documentation.
Also see the discussion in #1728.
To Reproduce
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 thewhen:
block.So I would expected that the
m.isStarted() >> true
holds up until the end of the feature, and should not be affected by the1 * m.start()
in thethen:
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
The text was updated successfully, but these errors were encountered: