Patricia Hallam-Mark
Patricia Hallam-Mark

Reputation: 11

How to run both JUnit5 plus Spock 2.0 tests in Gradle project

I have a simple project and I want to be able to run both JUnit 5 unit tests plus Spock 2 functional tests. If I have the Spock dependencies in the below build.gradle commented out, my JUnit5 tests run and pass. However, if I un-comment the Spock dependencies in preparation for adding a Spock test, the JUnit5 tests start failing.

my build.gradle:

buildscript {
    repositories {
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath(
          "org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE",
          'net.researchgate:gradle-release:2.8.0'
          )
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'net.researchgate.release'
apply plugin: 'groovy'

repositories {
    mavenCentral()
    jcenter()
}

sourceCompatibility = 11
targetCompatibility = 11

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    testImplementation 'org.codehaus.groovy:groovy:3.0.5'
    testImplementation group: 'org.spockframework', name: 'spock-spring', version: '2.0-M3-groovy-3.0'
    testImplementation group: 'org.spockframework', name: 'spock-core', version: '2.0-M3-groovy-3.0'
    //testImplementation group: 'org.spockframework', name: 'spock-junit4', version: '2.0-M3-groovy-3.0'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
}

test {
    useJUnitPlatform()
}

jar {
   enabled = true
}

bootJar {
    archiveFileName = "app.jar"
}

The error I am getting if I un-comment the Spock dependencies:

org.gradle.api.internal.tasks.testing.TestSuiteExecutionException: Could not complete execution for Gradle Test Executor 3.
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:63)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy2.stop(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.util.ServiceConfigurationError: org.junit.platform.engine.TestEngine: org.spockframework.runtime.SpockEngine Unable to get public no-arg constructor
    at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:581)
    at java.base/java.util.ServiceLoader.getConstructor(ServiceLoader.java:672)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1232)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1264)
    at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1299)
    at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1384)
    at java.base/java.lang.Iterable.forEach(Iterable.java:74)
    at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:87)
    at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:67)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:97)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
    ... 25 more
Caused by: java.lang.NoClassDefFoundError: org/junit/platform/engine/support/discovery/SelectorResolver
    at java.base/java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3137)
    at java.base/java.lang.Class.getConstructor0(Class.java:3342)
    at java.base/java.lang.Class.getConstructor(Class.java:2151)
    at java.base/java.util.ServiceLoader$1.run(ServiceLoader.java:659)
    at java.base/java.util.ServiceLoader$1.run(ServiceLoader.java:656)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.util.ServiceLoader.getConstructor(ServiceLoader.java:667)
    ... 36 more
Caused by: java.lang.ClassNotFoundException: org.junit.platform.engine.support.discovery.SelectorResolver
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    ... 44 more

Upvotes: 1

Views: 3078

Answers (2)

Katia Savina
Katia Savina

Reputation: 375

I ended up using both old and new JUnit engines:

test.useJUnitPlatform() {
        includeEngines 'junit-vintage'
        includeEngines 'junit-jupiter'
    }

, where vintage is for Spock, and jupiter is for JUnit5.

It may not be the best solution, but it works :)

Upvotes: 0

Rob Evans
Rob Evans

Reputation: 2874

I created a base_app here: https://github.com/robevansuk/base_app/blob/master/build.gradle

group 'com.example'
version '1.0'

apply plugin: 'groovy'
apply plugin: 'java'

sourceCompatibility = 1.8

test { useJUnitPlatform() }

repositories {
  mavenCentral()
}

dependencies {
  implementation 'org.codehaus.groovy:groovy-all:3.0.6'
  implementation 'org.springframework:spring-context:5.3.1'

  testImplementation 'org.junit.jupiter:junit-jupiter:5.7.0'
  testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
  testImplementation 'org.spockframework:spock-core:2.0-M4-groovy-3.0'
}

sourceSets {
  main {
    groovy {
      srcDirs = ['src/main/java', 'src/main/groovy']
    }
    resources {
      srcDirs = ['src/main/resources']
    }
  }
}

When I just bumped everything to the latest versions I got an error warning me of version incompatibilities. The resulting page visited contained the below tables, but not well formatted. So I've formatted them to be more readable and included them below:

| Spock version | Groovy version | JUnit version | Grails version | Spring version |
|:--------------|:---------------|:--------------|:---------------|:---------------|
| 0.5-groovy-1.6 | 1.6.1-1.6.x | 4.7-4.x | 1.2.0-1.2.x | 2.5.0-3.x |
| 0.5-groovy-1.7 | 1.7.0-1.7.x | 4.7-4.x | 1.3.0-1.3.x | 2.5.0-3.x |
| 0.6-groovy-1.7 | 1.7.0-1.7.x | 4.7-4.x | 1.3.0-1.3.x | 2.5.0-3.x |
| 0.6-groovy-1.8 | 1.8.1-1.8.x | 4.7-4.x | 2.0-2.x | 2.5.0-3.x |
| 0.7-groovy-1.8 | 1.8.1-1.8.x | 4.7-4.x | 2.0-2.x | 2.5.0-3.x |
| 0.7-groovy-2.0 | 2.0.0 -2.x.x | 4.7-4.x | 2.2-2.x | 2.5.0-3.x |
| 1.0-groovy-2.0 | 2.0.0 -2.2.x | 4.7-4.x | 2.2-2.x | 2.5.0-4.x |
| 1.0-groovy-2.3 | 2.3.0 -2.3.x | 4.7-4.x | 2.2-2.x | 2.5.0-4.x |
| 1.0-groovy-2.4 | 2.4.0 -2.x.x | 4.7-4.x | 2.2-2.x | 2.5.0-4.x |

| Spock version | Groovy version | JUnit version | Grails version | Spring version |
|:--------------|:---------------|:--------------|:---------------|:---------------|
| 1.1-groovy-2.0-SNAPSHOT | 2.0.0 -2.2.x | 4.7-4.x | 2.2-2.x | 2.5.0-4.x |
| 1.1-groovy-2.3-SNAPSHOT | 2.3.0 -2.3.x | 4.7-4.x | 2.2-2.x | 2.5.0-4.x |
| 1.1-groovy-2.4-SNAPSHOT | 2.4.0 -2.x.x | 4.7-4.x | 2.2-2.x | 2.5.0-4.x |

Upvotes: 1

Related Questions