【问题标题】:Gradle - compileTestGroovy can't resolve main Application classGradle - compileTestGroovy 无法解析主应用程序类
【发布时间】:2019-06-02 03:33:33
【问题描述】:

我有一个奇怪的问题。我们的项目已经启动并运行了 6 年,一些软件包升级早就应该进行了。 应用后端使用 Java 8 编写,测试使用 Java 和 Groovy,前端使用 AngularJS 1.5

App 由 7 个模块组成,整个项目结构和构建过程是通过 gradle 构建文件设置的。

在更新库版本的过程中,最大的一个是 mongodb4.0 升级和 spring 升级到 5.1.3spring_boot 版本从 1.2.6 到 2.1.1

我知道,有不少重大升级,并且感谢我们进行的所有测试,我设法更改了所有代码以符合新版本库的更改。所有的测试都通过了。几乎所有模块的构建都像魅力一样工作。 除了包含 Groovy 测试类的模块。当我从 IntelliJ 运行它们时,所有测试都通过了,没有编译或构建错误。

但是当我尝试运行gradle build 时,任务testCompileGroovy 失败,因为无法解析抽象测试规范类之一中的导入。 @SpringBootTest 注解的 classes 参数需要主 Application 类的导入。

这里是 libraries.gradle 文件,其中包含我们定义的所有依赖库...

ext {
spring_version = "5.1.3.RELEASE"
spring_boot_version = "2.1.1.RELEASE"
spring_data_mongodb = "2.1.3.RELEASE"
groovy_version = "2.4.5"

ext.lib = [

        spring_core                 : "org.springframework:spring-core:$spring_version",
        spring_context              : "org.springframework:spring-context:$spring_version",
        spring_context_support      : "org.springframework:spring-context-support:$spring_version",
        spring_test                 : "org.springframework:spring-test:$spring_version",
        spring_data_mongodb         : "org.springframework.data:spring-data-mongodb:$spring_data_mongodb",
        spring_shell                : "org.springframework.shell:spring-shell:1.1.0.RELEASE",
        spring_webmvc               : "org.springframework:spring-webmvc:$spring_version",

        spring_web                  : "org.springframework:spring-web$spring_version",

        spring_boot_test            : "org.springframework.boot:spring-boot-test:2.1.1.RELEASE",

        spring_boot_starter         : "org.springframework.boot:spring-boot-starter:$spring_boot_version",
        spring_boot_starter_web     : "org.springframework.boot:spring-boot-starter-web:$spring_boot_version",
        spring_boot_starter_tomcat  : "org.springframework.boot:spring-boot-starter-tomcat:$spring_boot_version",
        spring_boot_starter_security: "org.springframework.boot:spring-boot-starter-security:$spring_boot_version",
        spring_boot_starter_test    : "org.springframework.boot:spring-boot-starter-test:$spring_boot_version",
        spring_boot_gradle_plugin   : "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_version",
        spring_boot_autoconfigure   : "org.springframework.boot:spring-boot-autoconfigure:$spring_boot_version",
        spring_boot_logging         : "org.springframework.boot:spring-boot-logging:$spring_boot_version",

        swager                      : "io.springfox:springfox-swagger2:2.6.1",
        swager_ui                   : "io.springfox:springfox-swagger-ui:2.6.1",

        groovy_all                  : "org.codehaus.groovy:groovy-all:$groovy_version",
        groovy_sql                  : dependencies.create("org.codehaus.groovy:groovy-sql:$groovy_version") {
            exclude group: "org.codehaus.groovy"
        },

        http_builder                : "org.codehaus.groovy.modules.http-builder:http-builder:0.7.1",
        httpmime                    : "org.apache.httpcomponents:httpmime:4.3.6",
        gmongo                      : dependencies.create("com.gmongo:gmongo:1.5") {
            exclude group: "org.codehaus.groovy"
        },
        postgresql                  : "org.postgresql:postgresql:9.4-1201-jdbc41",
        bonecp                      : "com.jolbox:bonecp:0.8.0.RELEASE",
        joda_time                   : "joda-time:joda-time:2.8.2",
        guava                       : "com.google.guava:guava:18.0",
        gson                        : "com.google.code.gson:gson:2.8.5",
        stripe                      : "com.stripe:stripe-java:1.37.0",
        jackson_annotations         : "com.fasterxml.jackson.core:jackson-annotations:2.4.4",
        logentries                  : "com.logentries:logentries-appender:1.1.30",
        hibernate_validator         : "org.hibernate:hibernate-validator:5.4.2.Final",
        logback_classic             : "ch.qos.logback:logback-classic:1.1.3",
        commons_lang                : "org.apache.commons:commons-lang3:3.1",
        commons_io                  : "commons-io:commons-io:2.4",
        commons_validator           : "commons-validator:commons-validator:1.4.0",
        httpclient                  : "org.apache.httpcomponents:httpclient:4.5.1",
        jasypt                      : "org.jasypt:jasypt:1.9.2",
        jsoup                       : "org.jsoup:jsoup:1.8.3",
        trimou_core                 : "org.trimou:trimou-core:1.8.2.Final",
        jackson_core                : "com.fasterxml.jackson.core:jackson-core:2.9.8",
        jackson_databind            : "com.fasterxml.jackson.core:jackson-databind:2.9.8",
        jackson_annotations         : "com.fasterxml.jackson.core:jackson-annotations:2.9.8",
        jackson_datatype_joda       : "com.fasterxml.jackson.datatype:jackson-datatype-joda:2.9.8",
        google_api_services_gmail   : dependencies.create("com.google.apis:google-api-services-gmail:v1-rev23-1.19.1") {
            exclude group: "com.google.guava"
        },
        google_http_client_jackson  : dependencies.create("com.google.http-client:google-http-client-jackson:1.19.0") {
            exclude group: "com.fasterxml.jackson.core"
        },
        javax_mail                  : "com.sun.mail:javax.mail:1.5.4",
        dnsjava                     : "dnsjava:dnsjava:2.1.7",
        email_reply_parser          : "./lib/EmailReplyParser-1.1.jar",
        salesforce                  : ["com.force.api:force-wsc:31.0.0", "com.force.api:force-partner-api:29.0.0", "com.force.api:force-metadata-api:29.0.0"],
        authy                       : 'com.authy:authy-java:1.1.0',
        libphonenumber              : 'com.googlecode.libphonenumber:libphonenumber:7.2.4',
        hellosign                   : 'com.hellosign:hellosign-java-sdk:4.0.5',
        awaitility                  : 'com.jayway.awaitility:awaitility:1.7.0',


        junit                       : "junit:junit:4.12",
        hamcrest_all                : "org.hamcrest:hamcrest-all:1.3",
        hamcrest_core               : "org.hamcrest:hamcrest-core:1.3",
        mockito_core                : "org.mockito:mockito-core:1.10.19",
        httpmime                    : "org.apache.httpcomponents:httpmime:4.3.6",
        rest_assured                : dependencies.create("com.jayway.restassured:rest-assured:2.4.1") {
            exclude group: "org.codehaus.groovy"
        },
        spock_core                  : "org.spockframework:spock-core:1.2-groovy-2.4",
        spock_spring                : "org.spockframework:spock-spring:1.2-groovy-2.4",

        apache_pdf                  : "org.apache.pdfbox:pdfbox:2.0.4",
        google_cloud                : "com.google.cloud:google-cloud-storage:1.35.0"
]}

这是失败的 tests-api 模块的 build.gradle 文件。

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

apply plugin: 'org.springframework.boot'

repositories {
    mavenCentral()
    maven {
        url "http://repo.springsource.org/libs-release"
    }
}

dependencies {
    compile project(':api')
    compile project(':cli')

    compile lib.groovy_all
    compile lib.http_builder
    compile lib.httpmime
    compile lib.gmongo
    compile lib.hamcrest_core

    testCompile lib.groovy_all
    testCompile lib.junit
    testCompile lib.spock_core
    testCompile lib.spock_spring
    testCompile lib.spring_boot_starter_test
}
api 模块的

build.gradle 如下所示:

    apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'org.springframework.boot'


buildscript {
    repositories {
        maven {
            url "http://repo.springsource.org/libs-release"
        }
        mavenLocal()
    }
    dependencies {
        classpath lib.spring_boot_gradle_plugin
    }
}

repositories {
    mavenCentral()
    maven {
        url "http://repo.springsource.org/libs-release"
    }
}

war {
    baseName = 'buyerdeck-api'
    version = '2.0'
}

dependencies {
    compile project(':backend')
    compile project(':analytics')

    compile lib.spring_webmvc
    compile lib.spring_boot_starter
    compile lib.spring_boot_starter_web
    compile lib.spring_boot_starter_tomcat
    compile lib.spring_boot_starter_security
    compile lib.jackson_core
    compile lib.jackson_annotations
    compile lib.jackson_datatype_joda

    compile lib.swager
    compile lib.swager_ui
    testCompile lib.junit
    testCompile lib.hamcrest_all
    testCompile lib.mockito_core
}

springBoot {
    mainClassName = "com.buyerdeck.Application"
}
backend 模块的

Aaaa 和 build.gradle

apply plugin: 'java'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
    maven {
        url "http://repo.springsource.org/libs-release"
    }
}

configurations {
    all*.exclude module: "groovy"
}

dependencies {
    compile project(':email')

    compile lib.spring_core
    compile lib.spring_context
    compile lib.spring_context_support
    compile lib.spring_data_mongodb

    compile lib.joda_time
    compile lib.guava
    compile lib.gson
    compile lib.stripe
    compile lib.jackson_core
    compile lib.jackson_databind
    compile lib.jackson_annotations
    compile lib.logentries
    compile lib.hibernate_validator
    compile lib.logback_classic
    compile lib.commons_lang
    compile lib.commons_io
    compile lib.commons_validator
    compile lib.httpclient
    compile lib.salesforce
    compile lib.jasypt
    compile lib.jsoup
    compile lib.trimou_core
    compile lib.hellosign
    compile lib.awaitility
    compile lib.authy
    compile lib.libphonenumber
    compile lib.httpmime
    compile lib.apache_pdf
    compile lib.google_cloud

    testCompile lib.spring_test
    testCompile lib.spring_boot_test
    testCompile lib.spring_boot_starter
    testCompile lib.junit
    testCompile lib.hamcrest_all
    testCompile lib.mockito_core
    testCompile lib.httpmime
    testCompile lib.rest_assured
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.11'
}

sourceSets {
    test {
        java {
            srcDir 'src/test/java'
            srcDir 'src/test-integration/java'
        }
    }
}

最后,引发编译错误的类是来自 tests-api 模块的 ApiSpecification.groovy:

    package tests.api

import com.companyxyz.Application
import com.companyxyz.backend.core.tenant.Tenant
import com.companyxyz.backend.infrastructure.mongo.MongoSetup
import org.bson.types.ObjectId
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.web.server.LocalServerPort
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.PropertySource
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.junit4.SpringRunner
import org.springframework.test.context.web.WebAppConfiguration
import spock.lang.Specification

@PropertySource("classpath:companyxyz.properties")
@SpringBootTest(classes = Application, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = ["server.port:0", "mongo.database:companyxyz-test-api", "email.templates.root.path:../email-templates", "email.enabled:false", "timegate.enabled:true"])
abstract class ApiSpecification extends Specification {

    @LocalServerPort
    private int serverPort

    @Value('${mongo.database}')
    private String dbName

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    MongoSetup mongoSetup;

    private static boolean dbCleaned;

    def setup() {
        ApiSettings.apiUrl = "http://localhost:$serverPort/api/"
        ApiSettings.dbName = dbName

        println "apiurl $ApiSettings.apiUrl"
        if (!dbCleaned) {
            println "Dropping Mongo DB $dbName"
            mongoTemplate.getDb().drop();
            mongoSetup.ensureIndexes()
            dbCleaned = true;
        }
        DbExecutor.createMockThingies()
    }

    def removeUser(email) {
        mongoTemplate.remove(Query.query(Criteria.where("email").is(email)), com.companyxyz.backend.core.user.User.class)
    }


}

错误在第 3 行:

导入 com.companyxyz.Application

无法解析导入。 testGroovyCompile 任务由于未解决的依赖关系而失败。直接从扩展该类的类运行测试没有任何问题。

该模块的 build.gradle 文件中的任何内容都没有更改,只是添加了一个 spring 测试所需的依赖项,但其他所有内容都与以前相同。 该模块依赖于其他模块,但除了所需的测试依赖项之外,它们的构建文件没有太大变化。

我花了好几个小时试图解决这个问题,但我就是不明白为什么它不起作用。我尝试了不同的 gradle 版本,但没有成功。有谁知道这些问题的原因可能是什么?

抱歉,帖子太长了,如果我能提供更多信息,请告诉我。

卢卡

【问题讨论】:

  • 看我的回答。我建议您先尝试解决方案 1)

标签: java gradle groovy dependency-injection build


【解决方案1】:

问题是您的api 模块是一个Spring Boot 项目:默认情况下它不会产生一个标准 jar,而只会产生一个executable/fat @ 987654325@(或war,如果您应用了war 插件)。 即使你在tests-api 模块中添加一个“项目”依赖compile project(':api'),Gradle 也无法将api 模块中的类提供给tests-api 的类路径,因为没有标准的jar 内置来自api模块(查看更多关于项目依赖类型here的细节):

[项目]“lib”依赖是一种特殊形式的执行依赖。它导致首先构建另一个项目,并将具有另一个项目的类的 jar 添加到类路径中。它还将其他项目的依赖项添加到类路径中。

所以我看到两个选项来解决您的问题:

1) (PREFERRED) 在api 模块中配置SpringBoot 插件以生成标准的jar

来自 api 模块的 build.gradle

jar {
    enabled = true
}

见:https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/gradle-plugin/reference/html/#packaging-executable-and-normal

2) 创建从 tests-apiapi 模块 SourceSet 的依赖关系:

来自 tests-api 模块的 build.gradle

dependencies {
    compile project(':api').sourceSets.main.output
    // others
}

(解决方案 2 应该可以工作,但未经测试。可能导致 api 项目依赖项在 tests-api 模块中不可用的错误)

【讨论】:

  • 非常感谢!!!实际上,在发布问题之后,我昨天就使用第二个选项让它工作了。但这似乎是一个黑客行为。我肯定也会尝试第一个选项并接受您的回答。最让我困扰的是,以前的项目是用相同的脚本构建的,没有问题。我认为 war 任务提供了与 jar 相同的输出以及一些。我肯定会更深入地阅读 gradle 构建任务。再次感谢您的帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-23
  • 2021-11-01
  • 2017-12-29
  • 2022-07-17
  • 2021-02-18
  • 1970-01-01
相关资源
最近更新 更多