Skip to content
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

Cannot cast BooleanAssert to Boolean when using assertj-core:3.25.3 StringAssert's in a Spock then block #1897

Closed
ocindev opened this issue Feb 28, 2024 · 5 comments

Comments

@ocindev
Copy link

ocindev commented Feb 28, 2024

Describe the bug

In the 3.25.3 release of assertj-core a feature was added that allows any StringAssert to be interpreted and asserted as a boolean value through the AbstractStringAssert#asBoolean() method. asBoolean() returns a BooleanAssert instance to allow further method chaining with boolean assertions.

The then block in a Spock test feature wraps any assertion code line with a Groovy Power Assert assert under the hood and expects the actual assertion to be evaluated as a boolean value.
This conflicts with the Groovy built-in org.codehaus.groovy.runtime.DefaultGroovyMethods#asBoolean(java.lang.Object) that Spock is using on anything that is not a Boolean value.

In the end this produces ClassCastExceptions for any usage of StringAssert from assertj.

To Reproduce

import spock.lang.Specification

import static org.assertj.core.api.Assertions.assertThat

class DemoSpec extends Specification {
    def 'assert some integer'() {
        when:
        def someInteger = 10

        then:
        assertThat(someInteger).isEqualTo(10)
    }

    def 'assert some string'() {
        when:
        def someString = 'some string'

        then:
        assertThat(someString).isEqualTo('some string')
    }
}

Expected behavior

All tests are successful.

Actual behavior

The assert some string feature fails due to a ClassCastException - BooleanAssert cannot be casted to Boolean.

Java version

openjdk 17.0.10 2024-01-16
OpenJDK Runtime Environment Temurin-17.0.10+7 (build 17.0.10+7)
OpenJDK 64-Bit Server VM Temurin-17.0.10+7 (build 17.0.10+7, mixed mode)

Buildtool version


Gradle 8.6

Build time: 2024-02-02 16:47:16 UTC
Revision: d55c486870a0dc6f6278f53d21381396d0741c6e

Kotlin: 1.9.20
Groovy: 3.0.17
Ant: Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM: 17.0.10 (Eclipse Adoptium 17.0.10+7)
OS: Mac OS X 14.2.1 aarch64

What operating system are you using

Mac

Dependencies

  • org.apache.groovy:groovy-all:4.0.18
  • org.spockframework:spock-core
  • org.spockframework:spock-bom:2.3-groovy-4.0
  • org.spockframework:spock-junit4
  • org.assertj:assertj-core:3.25.3

Additional context

No response

@AndreasTu
Copy link
Member

Can you expain the reason, why you want to write:

then:
assertThat(someInteger).isEqualTo(10)
assertThat(someString).isEqualTo('some string')

instead of:

then:
someInteger == 10
someString == 'some string'

The Spock power asserts are shorter to write and have a better error message than the AssertJ assertions.

Note: Since 2.4-M2: If you want to suppress the assertion you can write !! before a line to prevent assertions.

then:
!!assertThat(someInteger).isEqualTo(10)

See Opt-out of condition handling for details.

@AndreasTu
Copy link
Member

Also here is a reproducer without AssertJ dependency:

class DemoSpec extends Specification {
    def 'assert some string'() {
        when:
        def o = new TestAssertStub()

        then:
        o.func()
    }
    
    static class TestAssertStub{
        TestAssertStub func(){
            return this
        }
        
        String asBoolean(){
            return "STR"
        }
    }
}

Throws:

java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Boolean

@AndreasTu
Copy link
Member

AndreasTu commented Feb 29, 2024

I am really not sure here, because this also break, when Spock is not involved, but only Groovy:

def o = new TestAssertStub()
assert o.func()

class TestAssertStub{
    TestAssertStub func(){
        return this
    }

    String asBoolean(){
        return "STR"
    }
}

AssertJ does not play well here with the Groovy sematic to use the method asBoolean() to convert it to a boolean.

Maybe we can fix the spock part when such a thing is used in a then: block,
but the general issue when combined with a normal Groovy assert can't be solved by Spock.
I also commented that on the original issue in the AssertJ repo.

@leonard84
Copy link
Member

I don't think there is anything for us to fix, as @AndreasTu already pointed out we have the opt-out operator, but in this particular case the asBoolean conflicts with Groovy's default methods.

@leonard84 leonard84 closed this as not planned Won't fix, can't repro, duplicate, stale Feb 29, 2024
@scordio
Copy link

scordio commented Feb 29, 2024

@leonard84 @AndreasTu I'd be happy to get your thoughts on assertj/assertj#3381 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants