jenkins-pipeline - Jenkins-spock:方法存根失败取决于平台
问题描述
这是我编写的一段(简化的)代码和相关的单元测试,直到最近我都对此感到高兴。
文件 vars/deleteFile.groovy
@NonCPS
def call(String path) {
new File(path).delete() //Must be declared as authorized class & method in Jenkins
}
文件 vars/toto.groovy:
def call(Map params = [:] ) {
...
deleteFile(params.get('envFile'))
...
}
文件测试/vars/TotoSpec.groovy:
class TotoSpec extends JenkinsPipelineSpecification {
def toto = null
def setup() {
toto = loadPipelineScriptForTest('vars/toto.groovy')
...
}
def '[toto] test env file'() {
when:
toto envFile: 'env.list'
then:
...
1 * getPipelineMock('deleteFile.call').call('env.list')
}
}
该测试过去在我的本地机器和 CI 从站上都通过了。但是,我不知道为什么,这在我的本地机器上开始失败(但不是在从属机器上):
java.lang.IllegalStateException:
There is no pipeline step mock for [deleteFile.call].
1. Is the name correct?
2. Does the pipeline step have a descriptor with that name?
3. Does that step come from a plugin? If so, is that plugin listed as a dependency in your pom.xml?
4. If not, you may need to call explicitlyMockPipelineStep('deleteFile.call') in your test's setup: block.
at TotoSpec.[toto] test env file(TotoSpec.groovy:90)
因此,我对我的单元测试执行了以下更新,但我不确定是否deleteFile
真的是一个管道步骤,因为它没有主体/闭包。
文件测试/vars/TotoSpec.groovy:
class TotoSpec extends JenkinsPipelineSpecification {
def setup() {
toto = loadPipelineScriptForTest('vars/toto.groovy')
explicitlyMockPipelineStep('deleteFile')
...
}
def '[toto] test env file'() {
when:
toto envFile: 'env.list'
then:
...
1 * getPipelineMock('deleteFile').call('env.list')
}
}
现在单元测试在我的本地机器上正常,但在 CI 从站上失败:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'Mock Generator for [deleteFile]' with class 'com.homeaway.devtools.jenkins.testing.PipelineVariableImpersonator' to class 'groovy.lang.Closure'
at TotoSpec.setup(TotoSpec.groovy:32)
我错过了什么?
本地配置:
$ java --version
openjdk 14.0.2 2020-07-14
OpenJDK Runtime Environment (build 14.0.2+12-Ubuntu-120.04)
OpenJDK 64-Bit Server VM (build 14.0.2+12-Ubuntu-120.04, mixed mode, sharing)
mvn --version
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 14.0.2, vendor: Private Build, runtime: /usr/lib/jvm/java-14-openjdk-amd64
Default locale: en, platform encoding: UTF-8
OS name: "linux", version: "4.19.128-microsoft-standard", arch: "amd64", family: "unix"
CI 从站配置:
$ java --version
openjdk 11.0.6 2020-01-14
OpenJDK Runtime Environment (build 11.0.6+10-post-Debian-1bpo91)
OpenJDK 64-Bit Server VM (build 11.0.6+10-post-Debian-1bpo91, mixed mode)
$ /home/jenkins/tools/hudson.tasks.Maven_MavenInstallation/Maven_3.6.3/apache-maven-3.6.3/bin/mvn --version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: /home/jenkins/tools/hudson.tasks.Maven_MavenInstallation/Maven_3.6.3/apache-maven-3.6.3
Java version: 11.0.6, vendor: Debian, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: fr_FR, platform encoding: UTF-8
OS name: "linux", version: "4.9.0-14-amd64", arch: "amd64", family: "unix"
pom.xml 中的依赖项
<properties>
<groovy.core.version>2.4.17</groovy.core.version>
<groovy.gmaven.pluginVersion>1.6.1</groovy.gmaven.pluginVersion>
<google.guava.version>20.0</google.guava.version>
<jenkins-spock.version>2.0.0</jenkins-spock.version>
<jenkins.version>2.102</jenkins.version>
<jenkins.servlet.version>3.1.0</jenkins.servlet.version>
<jenkins.workflow.cps.version>2.36</jenkins.workflow.cps.version>
<jenkins.workflow.basic.steps.version>2.6</jenkins.workflow.basic.steps.version>
<jenkins.workflow.durable.task.step.version>2.21</jenkins.workflow.durable.task.step.version>
<jenkins.workflow.stage.step.version>2.3</jenkins.workflow.stage.step.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<junit.plugin.version>1.24</junit.plugin.version>
<surefire.pluginVersion>2.22.0</surefire.pluginVersion>
<logback.configration>logback-test.xml</logback.configration>
<logdir>${project.build.directory}/log</logdir>
<test.loglevel>ERROR</test.loglevel>
<log.logback.version>1.2.3</log.logback.version>
<log.slf4j.version>1.7.25</log.slf4j.version>
</properties>
...
<dependencies>
<dependency>
<groupId>com.homeaway.devtools.jenkins</groupId>
<artifactId>jenkins-spock</artifactId>
<version>${jenkins-spock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${log.logback.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${log.logback.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-core</artifactId>
<version>${jenkins.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-basic-steps</artifactId>
<version>${jenkins.workflow.basic.steps.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<version>${jenkins.workflow.cps.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<!-- provides sh() step -->
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-durable-task-step</artifactId>
<version>${jenkins.workflow.durable.task.step.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<!-- provides stage() step -->
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>pipeline-stage-step</artifactId>
<version>${jenkins.workflow.stage.step.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${jenkins.servlet.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>junit</artifactId>
<version>${junit.plugin.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>${groovy.core.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${log.slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${log.slf4j.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
解决方案
再次仔细阅读文档,由于deleteFile
是我自己在vars
目录中声明的,所以它被认为是一个管道共享库全局变量。
因此,切换到以下单元测试现在在任何地方都可以正常工作:
class TotoSpec extends JenkinsPipelineSpecification {
def setup() {
toto = loadPipelineScriptForTest('vars/toto.groovy')
explicitlyMockPipelineVariable('deleteFile')
...
}
def '[toto] test env file'() {
when:
toto envFile: 'env.list'
then:
...
1 * getPipelineMock('deleteFile.call').call('env.list')
}
}
不过,目前还不清楚为什么我突然需要explicitlyMockPipelineVariable('deleteFile')
在我的机器上使用。
推荐阅读
- java - 使用JDK 10时找不到javax.annotation.Resource的lookup()方法
- excel - 将数据导出到文本文件
- php - 在 PHP 中 JSON 对象的开头和结尾添加单引号
- vue.js - 尝试使用道具将数据传递给全局对象,但无法获取要显示的数据
- r - 如何在 R 的 rugarch 包中使用分布图
- python - 在异步睡眠期间检查新的控制命令
- r - 在练习中创建箱线图
- xamarin - 如何在 Xamarin Forms 中以适当的图像比例在 UWP 中设置 SpashScreen?
- javascript - 编写一个满足以下测试的函数 f
- ios - NSInvalidArgumentException:Workout_Tracker.QuickAddViewController collectionView:numberOfItemsInSection:]:无法识别的选择器发送到实例