我有一个共享库,它调用管道步骤方法(withCredentials)。我试图测试withCredentails方法在调用myMethodToTest时是否已通过sh脚本正确调用,但遇到错误:
class myClass implements Serializable{
def steps
public myClass(steps) {this.steps = steps}
public void myMethodToTest(script, String credentialsId) {
steps.withCredentials([[$class: ‘UsernamePasswordMultiBinding’, credentialsId: "${credentialsId}", usernameVariable: ‘USR’, passwordVariable: ‘PWD’]]) {
steps.sh """
export USR=${script.USR}
export PWD=${script.PWD}
$mvn -X clean deploy
"""
}
}
}
//模拟
class Steps {
def withCredentials(List args, Closure closure) {}
}
class Script {
public Map env = [:]
}
//测试用例
def "testMyMethod"(){
given:
def steps = Mock(Steps)
def script = Mock(Script)
def myClassObj = new myClass(steps)
script.env['USR'] = "test-user"
when:
def result = myClassObj.myMethodToTest(script, credId)
then:
1 * steps.withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: "mycredId", usernameVariable: 'USR', passwordVariable: 'PWD']])
1 * steps.sh(shString)
where:
credId | shString
"mycredId" | "export USR='test-user'"
//错误
Too few invocations for:
1 * steps.withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: "mycredId", usernameVariable: ‘USR’, passwordVariable: ‘PWD’]]) (0 invocations)
Unmatched invocations (ordered by similarity):
1 * steps.withCredentials([['$class':'UsernamePasswordMultiBinding', 'credentialsId':mycredId, 'usernameVariable’:’USR’, 'passwordVariable':'PWD’]]
答案 0 :(得分:1)
在测试和应用程序类的代码中,您都有很多细微的错误,而不是那么细微的错误。因此,让我提供一个新的MCVE,我在其中修复了所有问题并评论了测试中的一些关键部分:
package de.scrum_master.stackoverflow.q59442086
class Script {
public Map env = [:]
}
package de.scrum_master.stackoverflow.q59442086
class Steps {
def withCredentials(List args, Closure closure) {
println "withCredentials: $args, " + closure
closure()
}
def sh(String script) {
println "sh: $script"
}
}
package de.scrum_master.stackoverflow.q59442086
class MyClass implements Serializable {
Steps steps
String mvn = "/my/path/mvn"
MyClass(steps) {
this.steps = steps
}
void myMethodToTest(script, String credentialsId) {
steps.withCredentials(
[
[
class: "UsernamePasswordMultiBinding",
credentialsId: "$credentialsId",
usernameVariable: "USR",
passwordVariable: "PWD"]
]
) {
steps.sh """
export USR=${script.env["USR"]}
export PWD=${script.env["PWD"]}
$mvn -X clean deploy
""".stripIndent()
}
}
}
package de.scrum_master.stackoverflow.q59442086
import spock.lang.Specification
class MyClassTest extends Specification {
def "testMyMethod"() {
given:
// Cannot use mock here because mock would have 'env' set to null. Furthermore,
// we want to test the side effect of 'steps.sh()' being called from within the
// closure, which also would not work with a mock. Thus, we need a spy.
def steps = Spy(Steps)
def myClass = new MyClass(steps)
def script = new Script()
script.env['USR'] = "test-user"
when:
myClass.myMethodToTest(script, credId)
then:
1 * steps.withCredentials(
[
[
class: 'UsernamePasswordMultiBinding',
credentialsId: credId,
usernameVariable: 'USR',
passwordVariable: 'PWD'
]
],
_ // Don't forget the closure parameter!
)
// Here we need to test for a substring via argument constraint
1 * steps.sh({ it.contains(shString) })
where:
credId | shString
"mycredId" | "export USR=test-user"
}
}