Some basics:
Groovy meta-class stuff only works for Groovy classes, not for Java classes. I.e. the Java class knows nothing about any defined meta-class overrides, only Groovy calling your Java class code does.
The JRE bootstrap class java.time.Year
is final
, i.e. you cannot by conventional means create mock instances. You would need to un-finalise the class using a special class-loaderwhile it is loaded. My own tool Sarek which is still under development offers this feature. Others like PowerMock provide more indirect ways of helping you to stub final classes by instrumenting the classes which call them.
The method Year.now()
which you want to stub is not just in a final
class but also static
. Spock does not have any on-board means of stubbing static methods except for Groovy methods. Again, your method is in a Java class and also called by a Java class, so that is not going to help you. Again Sarek or other tools such as PowerMock can help you there.
Here is a little sample for doing it in Sarek. I have just pushed a snapshot to Maven Central for you, so you should be able to use that.
<dependency>
<groupId>dev.sarek</groupId>
<artifactId>sarek</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>dev.sarek</groupId>
<artifactId>sarek-spock-extension</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
package de.scrum_master.stackoverflow.q65321086;
import java.time.LocalDate;
import java.time.Year;
import static java.time.Month.JANUARY;
public class SomeClass {
public LocalDate methodUnderTest() {
return Year.now()
.atMonth(JANUARY)
.atDay(1);
}
}
package de.scrum_master.stackoverflow.q65321086
import dev.sarek.agent.mock.MockFactory
import spock.lang.Specification
import spock.lang.Subject
import spock.lang.Unroll
import java.time.LocalDate
import java.time.Year
import static java.time.Month.JANUARY
import static net.bytebuddy.matcher.ElementMatchers.named
class SomeClassTest extends Specification {
@Subject
SomeClass classUnderTest = new SomeClass()
@Unroll
def "override static JRE method Year.now() for #year"() {
setup:
MockFactory<Year> mockFactory = MockFactory
.forClass(Year.class)
.mockStatic(
named("now"),
{ method, args -> false },
{ method, args, proceedMode, returnValue, throwable -> Year.of(year) }
)
.build()
expect:
classUnderTest.methodUnderTest() == expectedDate
cleanup:
mockFactory.close()
where:
year || expectedDate
2019 || LocalDate.of(2019, JANUARY, 1)
2020 || LocalDate.of(2020, JANUARY, 1)
2021 || LocalDate.of(2021, JANUARY, 1)
}
}
This test passes for me. There is no in-depth documentation or tutorial for Sarek yet other than pretty good JavaDoc (check the sources) and lots of sample tests in different modules.
As for Sarek, I am planning to integrate it into Spock even better than now so using it will feel mock "spocky" in the future. I have just been very busy lately. But it is fully usable already and also comes with integrations into JUnit 4, Junit 5, TestNG.