spring-bootgradlebuild.gradledependency-managementspring-boot-gradle-plugin

Cannot use Gradle to test spring-boot code in separate test module, throws NoClassDefFoundError


I created a project

- frog
  -- frog-web
  -- frog-test
site/weic/grog/web/FrogWebApplication
java.lang.NoClassDefFoundError: site/weic/grog/web/FrogWebApplication
    at site.weic.frog.test.A01Test.a(A01Test.java:16)
    ...

How should I configure it so that I can unit test the frog-web's classes in the frog-test module? THANKS!!!

This the code

frog

buildscript {
    repositories {
        mavenLocal()
        mavenCentral()
    }

    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.3.12.RELEASE")
    }
}

allprojects {
    apply plugin: 'java-library'
    apply plugin: 'org.springframework.boot'
    group 'site.weic'
    version 'dev-v0.2-SNAPSHOT'
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    tasks.withType(JavaCompile) {
        options.encoding 'UTF-8'
    }
    repositories {
        mavenLocal()
        maven { url 'https://maven.aliyun.com/repository/public' }
        mavenCentral()
    }
    bootJar {
        enabled false
    }
}

subprojects {
    apply plugin: 'io.spring.dependency-management'
    dependencies {
        annotationProcessor 'org.projectlombok:lombok'
        compileOnly 'org.projectlombok:lombok'
        implementation 'org.slf4j:slf4j-api'
    }
    dependencyManagement {
        dependencies {
            dependency "org.projectlombok:lombok:1.18.26"
            dependency "mysql:mysql-connector-java:8.0.23"
        }
        imports {
            mavenBom "org.springframework.boot:spring-boot-starter-parent:2.3.12.RELEASE"
        }
    }
}

frog-web

@SpringBootApplication
public class FrogWebApplication {

    public static void main(String[] args) {
        SpringApplication.run(FrogWebApplication.class, args);
    }
}
bootJar {
    enabled true
}
dependencies {
    api 'org.springframework.boot:spring-boot-starter-web'
}

frog-test

public class A01Test {

    @Test
    public void a(){
        // Here to test whether frog-web's classes can be access in module frog-test, 
        // NoClassDefFoundError will be thrown
        final FrogWebApplication web = new FrogWebApplication();
        System.out.println(123);
    }
}
dependencies {
    implementation project(":frog-web")
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

Solution

  • Spring Boot creates a fat/executable jar with a slightly different structure (see the Spring Boot Reference Guide). You cannot use this jar as a dependency for other projects due to this difference.

    How to create an additional artifact that can be used as a dependency is explained in the Spring Boot Reference Guide as well.

    However it is strange that you seperated your tests from the actual artifact. If they are integration tests, use your test script to launch the application and fire of http requests and validate those, don't directly reference the classes for this.