You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jenkins Test Harness + Spock单元测试Jenkins Job DSL脚本时遭遇Jenkins.instance缺失异常

Jenkins Test Harness + Spock单元测试Jenkins Job DSL脚本时遭遇Jenkins.instance缺失异常

看起来你遇到的问题核心是测试代码里的JobManagement没有关联到Jenkins Test Harness启动的测试实例,而是默认去查找全局的Jenkins.instance,但这个全局实例在测试环境中并没有被正确绑定(从你打印的jenkinsRule.instance为null也能看出来,新版本的测试 harness 已经不再用instance字段了)。下面给你几个具体的解决步骤:

1. 修正Jenkins实例的获取方式,关联测试实例到JobManagement

你当前用的JenkinsJobManagement默认会通过全局查找获取Jenkins实例,但测试环境里的实例是由JenkinsRule创建的独立实例,需要手动让JobManagement使用这个实例。修改你的测试类代码:

package com.example

import groovy.util.FileNameFinder
import javaposse.jobdsl.dsl.DslScriptLoader
import javaposse.jobdsl.plugin.JenkinsJobManagement
import javaposse.jobdsl.plugin.LookupStrategy
import org.junit.ClassRule
import org.jvnet.hudson.test.JenkinsRule
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll

class JobRulesSpec extends Specification {
    @Shared
    @ClassRule
    private JenkinsRule jenkinsRule = new JenkinsRule()

    @Unroll
    def 'test script #file.name'() {
        given:
        // 改用jenkinsRule.jenkins获取测试实例,旧的instance字段已被废弃
        def testJenkins = jenkinsRule.jenkins
        println "==============> ${testJenkins}"
        
        // 创建自定义JobManagement,强制使用测试实例
        def jobManagement = new JenkinsJobManagement(System.out, [:], new File('.')) {
            @Override
            protected LookupStrategy createLookupStrategy() {
                return new LookupStrategy(LookupStrategy.Strategy.JENKINS_CONTEXT) {
                    @Override
                    protected Object getContext() {
                        return testJenkins
                    }
                }
            }
        }

        when:
        new DslScriptLoader(jobManagement).runScript(file.text)

        then:
        noExceptionThrown()

        where:
        file << new FileNameFinder().getFileNames('src/jobs', '**/*.groovy').collect { new File(it) }
    }
}

这段代码通过覆盖JenkinsJobManagement的createLookupStrategy方法,让它使用测试环境的Jenkins实例,而不是去全局查找。

2. 清理Gradle依赖中的冲突和重复声明

你的build.gradle里有不少重复的依赖声明(比如testImplementation和testCompile重复),还有Spock版本混用的问题(Groovy2.5配Spock2.0会不兼容),建议清理后改成这样:

plugins {
    id 'groovy'
}

sourceSets {
    jobs {
        groovy {
            srcDirs 'src/jobs'
            compileClasspath += main.compileClasspath
        }
        compileClasspath += sourceSets.main.output
        runtimeClasspath += sourceSets.main.output
    }
    main {
        groovy {
            srcDir 'src/main/groovy'
        }
    }
    test {
        groovy {
            srcDir 'src/test/groovy'
        }
    }
}

repositories {
    mavenCentral()
    maven { url 'https://repo.jenkins-ci.org/releases/' }
}

configurations {
    testPlugins {}
    testCompile {
        exclude group: 'xalan'
        exclude group: 'xerces'
    }
}

configurations.all*.exclude group: 'xalan'

dependencies {
    implementation 'org.codehaus.groovy:groovy:2.5.14'
    implementation ("org.jenkins-ci.plugins:job-dsl-core:${jobDslVersion}") {
        exclude module: 'xstream'
    }

    // Spock版本要匹配Groovy2.5,用1.3-groovy-2.5
    testImplementation 'org.spockframework:spock-core:1.3-groovy-2.5'
    testImplementation 'cglib:cglib-nodep:2.2.2'

    // Jenkins测试工具依赖
    testImplementation('org.jenkins-ci.main:jenkins-test-harness:2146.v6b_f8b_1cb_d12d') {
        exclude group: 'org.netbeans.modules', module: 'org-netbeans-insane'
    }
    testImplementation("org.jenkins-ci.main:jenkins-war:${jenkinsVersion}") {
        exclude group: 'org.jenkins-ci.ui', module: 'bootstrap'
    }
    testImplementation "org.jenkins-ci.main:jenkins-core:${jenkinsVersion}"

    // Job DSL插件依赖
    testImplementation "org.jenkins-ci.plugins:job-dsl:${jobDslVersion}"
    testImplementation 'org.jenkins-ci.plugins:structs:1.20'
    testImplementation 'org.jenkins-ci.plugins:script-security:1.54'

    // 测试环境需要安装的插件
    testPlugins 'org.jenkins-ci.plugins:cloudbees-folder:5.14'
    testPlugins 'org.jenkins-ci.plugins:credentials:2.1.10'
    testPlugins 'org.jenkins-ci.plugins:cvs:2.13'
    testPlugins 'org.jenkins-ci.plugins:ghprb:1.40.0'
    testPlugins 'org.jenkins-ci.plugins:token-macro:2.5'
    testPlugins 'org.jenkins-ci.plugins.workflow:workflow-cps-global-lib:2.7'
}

task resolveTestPlugins(type: Copy) {
    from configurations.testPlugins
    into new File(sourceSets.test.output.resourcesDir, 'test-dependencies')
    include '*.hpi'
    include '*.jpi'

    def mapping = [:]
    doFirst {
        configurations.testPlugins.resolvedConfiguration.resolvedArtifacts.each {
            mapping[it.file.name] = "${it.name}.${it.extension}"
        }
    }
    rename { mapping[it] }
    doLast {
        List<String> baseNames = source*.name.collect { mapping[it] }.collect { it[0..it.lastIndexOf('.') - 1] }
        new File(destinationDir, 'index').setText(baseNames.join('\n'), 'UTF-8')
    }
}

test {
    dependsOn tasks.resolveTestPlugins
    inputs.files sourceSets.jobs.groovy.srcDirs
    useJUnitPlatform()
}

3. 检查版本兼容性(关键)

你用的Job DSL 1.77是2020年的老版本,而Jenkins 2.445是2024年的新版本,两者的API差异可能导致很多兼容性问题。建议:

  • 要么升级Job DSL到与Jenkins 2.445兼容的版本(比如Job DSL 1.85+)
  • 要么降低Jenkins版本到Job DSL 1.77支持的范围(比如Jenkins 2.289.x系列)

如果不想改版本,至少要确保所有依赖的版本相互匹配,避免API不兼容导致的实例初始化失败。

备注:内容来源于stack exchange,提问作者josselin chevalay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 07:19:39