spring-gradle-plugins / dependency-management-plugin

A Gradle plugin that provides Maven-like dependency management functionality
690 stars 88 forks source link

Dependency management breaks RestAssured Tests #265

Closed atetzner closed 4 years ago

atetzner commented 4 years ago

Description

Spring Dependency management removes the transitive dependencies of rest-assured to org.codehaus.groovy:groovy and org.codehaus.groovy:groovy-xml. This causes RestAssured tests to fail at runtime when using e.g. the body() method.

Steps to reproduce

  1. Create a new project using the files below
  2. When running ./gradlew test the test will run sucessfully.
  3. Now add Spring Dependency Management plugin by uncommenting the lines in the plugins and the dependencies block of the build.gradle.kts file and run ./gradlew test again. The test will fail with:
    io/restassured/path/json/mapper/factory/JohnzonObjectMapperFactory
    java.lang.NoClassDefFoundError:    io/restassured/path/json/mapper/factory/JohnzonObjectMapperFactory
    at io.restassured.config.RestAssuredConfig.<init>(RestAssuredConfig.java:41)
    at io.restassured.RestAssured.<clinit>(RestAssured.java:420)
    at com.example.demo.RestAssuredTest.init(RestAssuredTest.kt:12)
    [...]
    Caused by: java.lang.ClassNotFoundException:    io.restassured.path.json.mapper.factory.JohnzonObjectMapperFactory
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    [...]

Example project files

build.gradle.kts

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    //id("org.springframework.boot") version "2.2.2.RELEASE"
    //id("io.spring.dependency-management") version "1.0.8.RELEASE"
    kotlin("jvm") version "1.3.61"
    kotlin("plugin.spring") version "1.3.61"
}

group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")

    testImplementation("io.rest-assured:rest-assured:4.1.1")
    testImplementation("junit:junit:4.12")

    /*
    implementation("org.springframework.boot:spring-boot-starter")
    testImplementation("org.springframework.boot:spring-boot-starter-test") {
        exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
    }
    */
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "1.8"
    }
}

com.example.demo.RestAssuredTest

package com.example.demo

import io.restassured.RestAssured
import org.hamcrest.Matchers.`is`
import org.junit.Before
import org.junit.Test

class RestAssuredTest {

    @Before
    fun init() {
        RestAssured.port = 443
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com"
    }

    @Test
    fun doSomething() {
        RestAssured
            .given()
            .`when`()
            .contentType("application/json")
            .get("/todos/1")
            .then()
            .statusCode(200)
            .body("title", `is`("delectus aut autem"))
    }

}
wilkinsona commented 4 years ago

Spring Dependency management removes the transitive dependencies of rest-assured to org.codehaus.groovy:groovy and org.codehaus.groovy:groovy-xml

That doesn't appear to be the case. Here's the test runtime classpath without dependency management:

testRuntimeClasspath - Runtime classpath of compilation 'test' (target  (jvm)).
+--- org.jetbrains.kotlin:kotlin-reflect:1.3.61
|    \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.61
|         +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.3.61
|         \--- org.jetbrains:annotations:13.0
+--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.61
|    +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.61 (*)
|    \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61
|         \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.61 (*)
+--- io.rest-assured:rest-assured:4.1.1
|    +--- org.codehaus.groovy:groovy:2.5.6 -> 2.5.8
|    +--- org.codehaus.groovy:groovy-xml:2.5.6 -> 2.5.8
|    |    \--- org.codehaus.groovy:groovy:2.5.8
|    +--- org.apache.httpcomponents:httpclient:4.5.3 -> 4.5.10
|    |    +--- org.apache.httpcomponents:httpcore:4.4.12
|    |    \--- commons-codec:commons-codec:1.11 -> 1.13
|    +--- org.apache.httpcomponents:httpmime:4.5.3 -> 4.5.10
|    |    \--- org.apache.httpcomponents:httpclient:4.5.10 (*)
|    +--- org.hamcrest:hamcrest:2.1
|    +--- org.ccil.cowan.tagsoup:tagsoup:1.2.1
|    +--- io.rest-assured:json-path:4.1.1 -> 3.3.0
|    |    +--- org.codehaus.groovy:groovy-json:2.4.15 -> 2.5.8
|    |    |    \--- org.codehaus.groovy:groovy:2.5.8
|    |    +--- org.codehaus.groovy:groovy:2.4.15 -> 2.5.8
|    |    \--- io.rest-assured:rest-assured-common:3.3.0
|    |         +--- org.codehaus.groovy:groovy:2.4.15 -> 2.5.8
|    |         \--- org.apache.commons:commons-lang3:3.4 -> 3.9
|    \--- io.rest-assured:xml-path:4.1.1 -> 3.3.0
|         +--- org.codehaus.groovy:groovy-xml:2.4.15 -> 2.5.8 (*)
|         +--- org.codehaus.groovy:groovy:2.4.15 -> 2.5.8
|         +--- io.rest-assured:rest-assured-common:3.3.0 (*)
|         +--- org.apache.commons:commons-lang3:3.4 -> 3.9
|         +--- org.ccil.cowan.tagsoup:tagsoup:1.2.1
|         +--- javax.xml.bind:jaxb-api:2.2.12 -> 2.3.1
|         |    \--- javax.activation:javax.activation-api:1.2.0
|         +--- com.sun.xml.bind:jaxb-osgi:2.2.10
|         \--- org.apache.sling:org.apache.sling.javax.activation:0.1.0
|              \--- javax.activation:activation:1.1.1
\--- junit:junit:4.12
     \--- org.hamcrest:hamcrest-core:1.3 -> 2.1
          \--- org.hamcrest:hamcrest:2.1

And with dependency management:

+--- org.jetbrains.kotlin:kotlin-reflect:1.3.61
|    \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.61
|         +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.3.61
|         \--- org.jetbrains:annotations:13.0
+--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.61
|    +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.61 (*)
|    \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61
|         \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.61 (*)
+--- io.rest-assured:rest-assured:4.1.1
|    +--- org.codehaus.groovy:groovy:2.5.6
|    +--- org.codehaus.groovy:groovy-xml:2.5.6
|    |    \--- org.codehaus.groovy:groovy:2.5.6
|    +--- org.apache.httpcomponents:httpclient:4.5.3
|    |    +--- org.apache.httpcomponents:httpcore:4.4.6
|    |    +--- commons-logging:commons-logging:1.2
|    |    \--- commons-codec:commons-codec:1.9
|    +--- org.apache.httpcomponents:httpmime:4.5.3
|    |    \--- org.apache.httpcomponents:httpclient:4.5.3 (*)
|    +--- org.hamcrest:hamcrest:2.1
|    +--- org.ccil.cowan.tagsoup:tagsoup:1.2.1
|    +--- io.rest-assured:json-path:4.1.1
|    |    +--- org.codehaus.groovy:groovy-json:2.5.6
|    |    |    \--- org.codehaus.groovy:groovy:2.5.6
|    |    +--- org.codehaus.groovy:groovy:2.5.6
|    |    \--- io.rest-assured:rest-assured-common:4.1.1
|    |         +--- org.codehaus.groovy:groovy:2.5.6
|    |         \--- org.apache.commons:commons-lang3:3.4
|    \--- io.rest-assured:xml-path:4.1.1
|         +--- org.codehaus.groovy:groovy-xml:2.5.6 (*)
|         +--- org.codehaus.groovy:groovy:2.5.6
|         +--- io.rest-assured:rest-assured-common:4.1.1 (*)
|         +--- org.apache.commons:commons-lang3:3.4
|         +--- org.ccil.cowan.tagsoup:tagsoup:1.2.1
|         +--- javax.xml.bind:jaxb-api:2.3.1
|         |    \--- javax.activation:javax.activation-api:1.2.0
|         +--- com.sun.xml.bind:jaxb-osgi:2.3.0.1
|         \--- org.apache.sling:org.apache.sling.javax.activation:0.1.0
|              \--- javax.activation:activation:1.1.1
\--- junit:junit:4.12
     \--- org.hamcrest:hamcrest-core:1.3

As you can see, the Groovy dependencies are present in each case, just with slightly different versions (2.5.6 vs 2.5.8).

A more notable difference is with io.rest-assured:json-path where the versions are 4.1.1 and 3.3.0. It's this difference that is causing the problem and is due to Spring Boot's dependency management. Spring Boot 2.2.x uses REST Assured 3.3.x and you are trying to use 4.4.x. The documentation for Spring Boot's Gradle plugin describes how to customise the version of a managed dependency. In this particular case, you need to configure rest-assured.version to be 4.1.1:

extra["rest-assured.version"] = "4.1.1"

You'll also need to provide a replacement for Commons Logging which is excluded by Spring Boot's dependency management. Uncommenting the dependency on spring-boot-starter will accomplish that via spring-jcl.

atetzner commented 4 years ago

Thanks for ponting this out and sorry about the wrong error description. I investigated this problem in my productive project and found out that missing groovy and groovy-xml is the problem for this error. After that I built up this demo for the github issue and as the error message has been the same, I assumed the cause to be the same. Obviously this wasn't the case ...

In my productive code, rest-assured is pushed to 4.4.1 although spring dependency management should keep it at 3.3.0 ; this is also the reason for me to use 4.4.1 in this demo. As I didn't specify the rest-assured version anywhere in my code, I assumed spring dependencymanagement to set the version to 4.4.1 , but something other must mess up with my dependencies :(

Thanks for your help @wilkinsona !