spockframework / spock

The Enterprise-ready testing and specification framework.
https://spockframework.org
Apache License 2.0
3.56k stars 470 forks source link

Using Closures in GroovySpy Argument Constraints will not work as expected #1234

Closed orgi closed 4 years ago

orgi commented 4 years ago

Issue description

I converted some of our test code from using Mock to GroovyMock since we are mainly testing dynamic methods.

It seems like it is not possible to use any kind of looping construct as part of the argument constraints, e.g.

it.foo.any { elem ->
    elem
}

How to reproduce

Use the following piece of groovy code as part of some spec:

    class FooBar {
        Map foo(Map args) {
            args
        }
    }

    def 'finding bar in [test: [foo, bar]] as argument constraint will work when calling foo on a GroovyMock'() {
        given:
        FooBar fooBar = GroovySpy(FooBar)

        when:
        fooBar.foo(test: ['foo', 'bar'])

        then:
        1 * fooBar.foo { args ->
            args.test.any {
                it == 'bar'
            }
        }
    }

Putting a breakpoint inside the any {} closure reveals that every time I reach this breakpoint the value of it is 'foo'. However I would have expected that for the second time it becomes ' bar' to make the test pass...

Some time back this used to work for us. Now when creating this small example I could not get it working, neither using Spy or GroovySpy nor Mock or GroovyMock.

Hope I did not do any obvious mistake while creating the example.

Additional Environment information

Java/JDK

java version "1.8.0_201" Java(TM) SE Runtime Environment (build 1.8.0_201-b09) Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)

openjdk version "1.8.0_212-1-ojdkbuild" OpenJDK Runtime Environment (build 1.8.0_212-1-ojdkbuild-b04) OpenJDK 64-Bit Server VM (build 25.212-b04, mixed mode)

Groovy version

2.4 / 2.5 Tried both versions

Build tool version

Gradle

Using gradle 6.4

Operating System

Windows 10 2004

IDE

IntelliJ

Build-tool dependencies used

dependencies {
    implementation 'org.codehaus.groovy:groovy-all:2.5.+'
    implementation 'org.spockframework:spock-core:1.3-groovy-2.5'
    testImplementation 'cglib:cglib-nodep:2.2'
    testImplementation 'org.objenesis:objenesis:2.6'
}

Tried using the latest objensis / cglib, too:
dependencies {
    implementation 'org.codehaus.groovy:groovy-all:2.5.+'
    implementation 'org.spockframework:spock-core:1.3-groovy-2.5'
    testImplementation 'cglib:cglib:3.3.0'
    testImplementation 'org.objenesis:objenesis:3.1'
}
kriegaex commented 4 years ago

I can confirm the problem in Spock 1.3. What is interesting is that if I add some diagnostic output

1 * fooBar.foo { args ->
  args.test.any {
    println it
    it == 'bar'
  }
}

it unexpectedly prints 5 lines, not just 2:

foo
foo
foo
foo
foo

I also tried in Spock 2.0-M4-groovy-3.0 where it works as expected. The test passes and prints:

foo
bar
leonard84 commented 4 years ago

After a cursory look my guess is that this was fixed by #1205, so my suggestion would be to update to Spock 2.0-M4