Testing Groovy元类重写java.time.Year静态方法now(),但生产代码在运行时没有使用now()的重写行为

Testing Groovy元类重写java.time.Year静态方法now(),但生产代码在运行时没有使用now()的重写行为,testing,groovy,overriding,runtime,spock,Testing,Groovy,Overriding,Runtime,Spock,我试图重写java.time.Year类的public static方法now(),因为我希望它返回不同的值,而不仅仅是当前年份。在我的生产代码中,我有一个正在测试的方法,它使用Year.now()方法,如下所示: 测试中的Java类 公共类SomeClass{ public LocalDate methodUnderTest(){ 返回年份。现在() .每月(一月) .第(1)天; } } 在Spock groovy测试中,我试图通过以下方式重写java.time.Year.now()方法:

我试图重写java.time.Year类的public static方法now(),因为我希望它返回不同的值,而不仅仅是当前年份。在我的生产代码中,我有一个正在测试的方法,它使用Year.now()方法,如下所示:

测试中的Java类

公共类SomeClass{
public LocalDate methodUnderTest(){
返回年份。现在()
.每月(一月)
.第(1)天;
}
}
在Spock groovy测试中,我试图通过以下方式重写java.time.Year.now()方法: 我打算在我的生产代码methodUnderTest()方法中使用静态方法now()的重写行为

但是,该测试仅适用于2020年(当前年份),其他两个值2019和2021不起作用,因为生产代码中显然没有使用预期的重写行为。 为什么在运行时methodUnderTest()的生产代码中没有使用预期的重写行为?

一些基本知识:

  • Groovy元类的东西只适用于Groovy类,而不适用于Java类。也就是说,Java类不知道任何定义的元类重写,只有Groovy调用Java类代码才知道

  • JRE引导类
    java.time.Year
    final
    ,即您不能通过常规方法创建模拟实例。在加载类时,需要使用特殊的类装入器取消该类的最终确定。我自己的工具仍在开发中,它提供了此功能。其他类似PowerMock的方法提供了更间接的方法,通过检测调用它们的类来帮助您存根最终类

  • 您想要存根的方法
    Year.now()
    不仅在
    final
    类中,而且在
    static
    中。除了Groovy方法外,Spock没有任何在板上存根静态方法的方法。同样,您的方法位于Java类中,也被Java类调用,所以这对您没有帮助。同样,Sarek或其他工具(如PowerMock)可以在这方面帮助您

  • 这里有一个在沙瑞克做这件事的小例子。我刚刚为您推送了一个快照,所以您应该能够使用它

    
    戴夫·萨雷克
    萨瑞克
    1.0-快照
    测试
    戴夫·萨雷克
    萨瑞克-斯波克分机
    1.0-快照
    测试
    
    package de.scrum_master.stackoverflow.q65321086;
    导入java.time.LocalDate;
    导入java.time.Year;
    导入静态java.time.Month.一月;
    公共类{
    public LocalDate methodUnderTest(){
    返回年份。现在()
    .每月(一月)
    .第(1)天;
    }
    }
    
    package de.scrum_master.stackoverflow.q65321086
    导入dev.sarek.agent.mock.MockFactory
    导入spock.lang.Specification
    导入spock.lang.Subject
    导入spock.lang.Unroll
    导入java.time.LocalDate
    导入java.time.Year
    导入静态java.time.Month.一月
    导入静态net.bytebuddy.matcher.ElementMatchers.named
    类SomeClassTest扩展了规范{
    @主题
    SomeClass classUnderTest=新的SomeClass()
    @展开
    def“覆盖静态JRE方法Year.now()for#Year”(){
    设置:
    MockFactory MockFactory=MockFactory
    .forClass(年份.类)
    .mockStatic(
    命名为(“现在”),
    {方法,args->false},
    {method,args,proceedMode,returnValue,throwable->Year.of(Year)}
    )
    .build()
    期望:
    classUnderTest.methodUnderTest()==expectedDate
    清理:
    mockFactory.close()
    哪里:
    年份| |预期
    2019年| |当地日期(2019年1月1日)
    2020年| |本地日期(2020年1月1日)
    2021年| |当地日期(2021年1月1日)
    }
    }
    
    我通过了这次考试。除了非常好的JavaDoc(检查源代码)和不同模块中的大量示例测试之外,Sarek还没有深入的文档或教程

    至于Sarek,我计划将它集成到Spock中,甚至比现在更好,因此在将来使用它会让人感觉像是在模仿“spocky”。我最近很忙。但它已经完全可用,并且还集成到JUnit 4、JUnit 5和TestNG中。

    一些基本功能:

  • Groovy元类的东西只适用于Groovy类,而不适用于Java类。也就是说,Java类不知道任何定义的元类重写,只有Groovy调用Java类代码才知道

  • JRE引导类
    java.time.Year
    final
    ,即您不能通过常规方法创建模拟实例。在加载类时,需要使用特殊的类装入器取消该类的最终确定。我自己的工具仍在开发中,它提供了此功能。其他类似PowerMock的方法提供了更间接的方法,通过检测调用它们的类来帮助您存根最终类

  • 您想要存根的方法
    Year.now()
    不仅在
    final
    类中,而且在
    static
    中。除了Groovy方法外,Spock没有任何在板上存根静态方法的方法。同样,您的方法位于Java类中,也被Java类调用,所以这对您没有帮助。同样,Sarek或其他工具(如PowerMock)可以在这方面帮助您

  • 这里有一个在沙瑞克做这件事的小例子。我刚刚为您推送了一个快照,所以您应该能够使用它

    
    戴夫·萨雷克
    萨瑞克
    1.0-快照
    测试
    戴夫·萨雷克
    萨瑞克-斯波克分机
    1.0-快照
    测试
    
    package de.scrum_master.stackoverflow.q65321086;
    导入java.time.LocalDate;
    导入java.time.Year;
    导入静态java.time.Month.一月;
    公共类{
    public LocalDate methodUnderTest(){
    返回年份。现在()
    .每月(一月)
    .第(1)天;
    }
    }
    
    package de.scrum\u master.stackoverflow。
    
    class SomeClassSpec extends Specification {
    
      @Subject
      SomeClass classUnderTest = new SomeClass()
    
      def "test method with overriden behaviour"() {
    
        setup:
        Year.metaClass.'static'.now = { -> Year.of(year) }
    
        expect:
        classUnderTest .methodUnderTest() == expectedDate
    
        where:
        year           || expectedDate
        2019           || LocalDate.of(2019, JANUARY, 1)
        2020           || LocalDate.of(2020, JANUARY, 1)
        2021           || LocalDate.of(2021, JANUARY, 1)
      }
    }