简体   繁体   中英

Using Spock framework with Groovy 2.6+ to support Java 8+ syntax

I have a Java library compiled using JDK 9 syntax. But, I am using spock-core:1.0-groovy-2.4 , Which does not support JDK 8+ syntax. So, in my Java code, I can use lambdas, default methods, and method references. But, in my tests I cannot. I have to use a clunky workaround for lambdas where I write a Groovy closure, then cast it to a Function<...> using the as keyword. But, other syntax such as method references like Class::method simply will not compile. Below is the dependencies section of my build.gradle .

How can I upgrade it such that I am using a newer version of Groovy that supports newer versions of Java?

All of there documentation seems to be out of date, and only references up to 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'
  )
}

Even when working with Spock 1.2-groovy-2.4-SNAPSHOT and Groovy 3.0.0-alpha-1 you cannot directly use Java's lambda and method reference syntax, I just tested it in my sample Spock/Geb Maven project in IntelliJ IDEA. But even with Spock 1.1 and Groovy 2.4.7 it it quite simple and elegant to replace lambdas and method references without casting or as , as far as I saw in my quick test:

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
  }

}

Please notice the two different ways of calling System.out.println - your choice. ;-)

Console log:

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

What exactly are you missing?


Update: Somehow my old code using .map(String.&toUpperCase) is not working anymore after I changed some things in my Maven project. I wonder why it ever worked before. So I have updated the sample code.

Things have changed in 2020. Spock supports Groovy 3 (which supports Java 8+ enhancements, including lambda expression) starting with version 2.0-M2 .

For Gradle it should be enough to add a Spock's JAR dedicated for Groovy 3:

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

and enable JUnit Platform:

test {
    useJUnitPlatform()
}

Btw, as a person who developed support for Groovy 3 in Spock I gathered various aspects (including caveats) relating migration from Spock 1.3 to 2.0 in a blog post - it might be worth to read it :-).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM