spock-mockable icon indicating copy to clipboard operation
spock-mockable copied to clipboard

Overriding final of AtomicBoolean type doesn't work

Open TheFriendlyCoder opened this issue 2 years ago • 3 comments

I have been experimenting with Spock lately as a potential replacement for JUnit / Mockito in some unit tests I am working on and have been struggling with mocking of classes that have final fields and methods. I was hoping this Spock plugin might address at least some of my problems, but I can not get a very simple POC Spock test to work properly. The simplest example test I've found is shown below:

import java.util.concurrent.atomic.AtomicBoolean

@Mockable(AtomicBoolean)
class SampleTestSpec extends Specification {
    def "Test Final Mock" () {
        given:
        AtomicBoolean activeFlag = Mock(AtomicBoolean.class)
        activeFlag.get() >> [true, false]

        expect:
        // First true
        activeFlag.get()
        // Then false
        !activeFlag.get()
    }
}

I am quite new to Java and Spock so I am wondering if I am just doing something fundamentally wrong here, or if this is perhaps a bug with this plugin?

TheFriendlyCoder avatar Oct 28 '22 13:10 TheFriendlyCoder

Hi @TheFriendlyCoder,

that's a bit tricky. First of all the syntax is wrong. You either need to write

given:
    AtomicBoolean activeFlag = Mock(AtomicBoolean.class) {
        activeFlag.get() >> [true, false]
    }

or

given:
    AtomicBoolean activeFlag = Mock(AtomicBoolean.class) 
then:
    activeFlag.get() >> [true, false]

Other than that you can not get a value from a mock in the expect block. You can check for yourself if you create a minimal non final AtomicBoolean class. The specification isn't working in bare spock either.

public class AtomicBoolean {
    public boolean get() {
        return false;
    }
}

But even if you would this your specification AtomicBoolean can currently. Classes must not be loaded before trying to transform them. Unfortunately AtomicBoolean is loaded during startup by ByteBuddy itself before the mock transformation can kick in. This might change in future releases.

Regards Joke

joke avatar Oct 29 '22 14:10 joke

Thanks for the prompt reply.

So does this mean that mocking finals in the Java standard library is basically not supported by this plugin? Also, in your reply you suggested that this "might change in the future" - do you have a link to a feature request or future improvement that I could watch for progress updates on this plan?

TheFriendlyCoder avatar Nov 01 '22 11:11 TheFriendlyCoder

It's a little bit trickier than that.

Classes that are loaded before the agent starts can not be altered. So the restriction applies to some Java standard library classes but not all. Only classes used by ByteBuddy, the startup process of JUnit and maybe the built system. Basically it's a restriction on how this plugin works: Classes get altered during start so spock get do its normal mocking. The plugin does impose an alternative mocking mechanism. I should extend the section in the README.

Let's just put a feature label on this issue. But to be precise I don't see how to see how to implement this feature at the moment.

I'm currently working on a mechanism that mocked classes are detected automatically rather than using the @Mockable annotation

joke avatar Nov 02 '22 14:11 joke