【问题标题】:Using Spock framework with Groovy 2.6+ to support Java 8+ syntax使用带有 Groovy 2.6+ 的 Spock 框架来支持 Java 8+ 语法
【发布时间】:2018-04-25 15:31:06
【问题描述】:

我有一个使用 JDK 9 语法编译的 Java 库。但是,我使用的是 spock-core:1.0-groovy-2.4,它不支持 JDK 8+ 语法。因此,在我的 Java 代码中,我可以使用 lambda、默认方法和方法引用。但是,在我的测试中我不能。我必须对 lambdas 使用笨拙的解决方法,在其中编写 Groovy 闭包,然后使用 as 关键字将其转换为 Function<...>。但是,诸如Class::method 之类的方法引用之类的其他语法根本无法编译。下面是我的build.gradle 的依赖部分。

如何升级它以使用支持较新版本 Java 的较新版本 Groovy?

那里的所有文档似乎都已过时,并且只引用了 Groovy 2.4。

dependencies {
  testCompile(
    'junit:junit:4.12',
    'org.codehaus.groovy:groovy-all:2.4.4',
    'org.spockframework:spock-core:1.0-groovy-2.4',
    'org.springframework.boot:spring-boot:1.2.1.RELEASE',
    'cglib:cglib-nodep:2.2.2',
    'com.opencsv:opencsv:4.1'
  )
}

【问题讨论】:

  • 您是否尝试过引用您喜欢的版本(如果需要,将其从 spock 中排除)?
  • @cfrick 你的意思是,只需输入它,就像将行更改为org.codehaus.groovy:groovy-all:2.6.0?问题是以下几行也指定了 groovy 版本(据我所知,它们应该匹配)并且一旦我更改了 spock 版本,它就会告诉我没有为该版本定义 spock 库。但是,我无法接受这么多年过去了,没有办法合并 Java 8 语法。我只是错过了一些东西
  • 您可以使用org.spockframework:spock-core:1.2-groovy-2.4-SNAPSHOT,它没有锁定到 groovy-2.4,所以您应该能够使用 groovy 2.6 或 3,请注意这些是 alpha 版本,并且 spock 没有经过测试。

标签: java spring gradle groovy spock


【解决方案1】:

即使在使用 Spock 1.2-groovy-2.4-SNAPSHOT 和 Groovy 3.0.0-alpha-1 时,您也不能直接使用 Java 的 lambda 和方法引用语法,我只是在 IntelliJ IDEA 的示例 Spock/Geb Maven 项目中对其进行了测试.但即使使用 Spock 1.1 和 Groovy 2.4.7,就我在快速测试中看到的而言,替换 lambda 和方法引用而不使用强制转换或 as 也非常简单和优雅:

package de.scrum_master.stackoverflow

import groovy.transform.ToString
import groovy.transform.TupleConstructor
import spock.lang.Specification

class LambdaMethodRefTest extends Specification {

  def "Replace lambdas and method references in Groovy"() {
    given:
    def bookStream = [
      new Book("Fortran", "Fred", 1957, 57.99),
      new Book("Java in 3 Days", "Alice", 2005, 11.99),
      new Book("Java in 4 Days", "Bob", 2005, 22.99),
      new Book("Filter-Map-Reduce with Lambdas", "Claire", 2014, 33.99)
    ].stream()

    when:
    def mapReduceResult = bookStream
      .filter { it.year >= 2004 }
      .peek(System.out.&println)
      .map { it.author }
      .map { it.toUpperCase() }
      .peek { System.out.println(it) }
      .reduce("", { s1, s2 -> (s1.isEmpty()) ? s2 : s1 + ", " + s2 })

    then:
    mapReduceResult == "ALICE, BOB, CLAIRE"
  }

  @TupleConstructor
  @ToString(includeNames = true, includePackage = false)
  static class Book {
    String title, author; int year; double price
  }

}

请注意拨打System.out.println 的两种不同方式——您的选择。 ;-)

控制台日志:

LambdaMethodRefTest$Book(title:Java in 3 Days, author:Alice, year:2005, price:11.99)
ALICE
LambdaMethodRefTest$Book(title:Java in 4 Days, author:Bob, year:2005, price:22.99)
BOB
LambdaMethodRefTest$Book(title:Filter-Map-Reduce with Lambdas, author:Claire, year:2014, price:33.99)
CLAIRE

你到底错过了什么?


更新:不知何故,在我更改了 Maven 项目中的一些内容后,我使用 .map(String.&toUpperCase) 的旧代码不再工作了。我想知道为什么它以前工作过。所以我更新了示例代码。

【讨论】:

  • 谢谢,这很有道理。就一个问题。 Idk Groovy 很好,但是当 { i -> System.out.println(i)} 也可以工作时,为什么还要使用 {i -> System.out&.println(i)}?而且,为什么方法引用不起作用? {System.out::println} 使用“::”语法?那是我的问题,我习惯于对简单的单行代码使用方法引用,但在 Groovy 中会导致语法错误。
  • 你在哪里看到{i -> System.out&.println(i)}?我从来没有写过。我刚刚写了System.out.&println,这是你抱怨的方法参考不起作用。它确实有效,只是 Groovy 语法,而不是 Java 8。虽然前者是基于对象实例 (System.out) 的方法引用,但 String.&toUpperCase 是一个没有实例的示例。
  • 谢谢,我不清楚那是什么语法。我不知道 & 是干什么用的。也许我只需要了解一些细微的差异。但是,由于您的回答,我的方法参考现在有效。我很感激。
  • 请注意:我刚刚更新了示例代码和解释。
  • 非常感谢,这很有帮助!
【解决方案2】:

2020 年情况发生了变化。Spock 从版本 2.0-M2 开始支持 Groovy 3(支持 Java 8+ 增强功能,包括 lambda 表达式)。

对于 Gradle,添加一个专用于 Groovy 3 的 Spock 的 JAR 就足够了:

testImplementation('org.spockframework:spock-core:2.0-M2-groovy-3.0')

并启用 JUnit 平台:

test {
    useJUnitPlatform()
}

顺便说一句,作为在 Spock 中开发对 Groovy 3 支持的人,我在 blog post 中收集了与从 Spock 1.3 迁移到 2.0 相关的各个方面(包括警告) - 可能值得一读 :-)。

【讨论】:

    猜你喜欢
    • 2017-02-11
    • 2016-07-13
    • 2016-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-08
    相关资源
    最近更新 更多