使用 Spock 的 Groovy 共享库测试管道步骤方法

Shr*_*uti 4 groovy mocking jenkins spock jenkins-pipeline

我有一个调用管道步骤方法(withCredentials)的共享库。我正在尝试测试 withCredentails 方法是否在调用 myMethodToTest 时使用 sh 脚本正确调用,但面临错误:

\n\n
 class myClass implements Serializable{\n    def steps\n    public myClass(steps) {this.steps = steps}\n\n    public void myMethodToTest(script, String credentialsId) {\n        steps.withCredentials([[$class: \xe2\x80\x98UsernamePasswordMultiBinding\xe2\x80\x99, credentialsId: "${credentialsId}", usernameVariable: \xe2\x80\x98USR\xe2\x80\x99, passwordVariable: \xe2\x80\x98PWD\xe2\x80\x99]]) {\n             steps.sh """\n                export USR=${script.USR}\n                export PWD=${script.PWD}\n                $mvn -X clean deploy\n             """\n          }\n     }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

//模拟

\n\n
class Steps {\n   def withCredentials(List args, Closure closure) {}\n}\n\nclass Script {\n    public Map env = [:]\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

//测试用例

\n\n
def "testMyMethod"(){\n        given:\n        def steps = Mock(Steps)\n        def script = Mock(Script)\n        def myClassObj = new myClass(steps)\n        script.env[\'USR\'] = "test-user"\n\n        when:\n        def result = myClassObj.myMethodToTest(script, credId)\n\n        then:\n        1 * steps.withCredentials([[$class: \'UsernamePasswordMultiBinding\', credentialsId: "mycredId", usernameVariable: \'USR\', passwordVariable: \'PWD\']])  \n        1 * steps.sh(shString)\n\n        where:\n        credId | shString\n        "mycredId" | "export USR=\'test-user\'"\n
Run Code Online (Sandbox Code Playgroud)\n\n

//错误

\n\n
Too few invocations for:\n\n1 * steps.withCredentials([[$class: \'UsernamePasswordMultiBinding\', credentialsId: "mycredId", usernameVariable: \xe2\x80\x98USR\xe2\x80\x99, passwordVariable: \xe2\x80\x98PWD\xe2\x80\x99]])   (0 invocations)\n\nUnmatched invocations (ordered by similarity):\n\n1 * steps.withCredentials([[\'$class\':\'UsernamePasswordMultiBinding\', \'credentialsId\':mycredId, \'usernameVariable\xe2\x80\x99:\xe2\x80\x99USR\xe2\x80\x99, \'passwordVariable\':\'PWD\xe2\x80\x99]]\n
Run Code Online (Sandbox Code Playgroud)\n

kri*_*aex 5

您的代码中存在大量微妙和不那么微妙的错误,包括测试类和应用程序类。因此,让我提供一个新的MCVE,其中我修复了所有内容并评论了测试中的一些关键部分:

package de.scrum_master.stackoverflow.q59442086

class Script {
  public Map env = [:]
}
Run Code Online (Sandbox Code Playgroud)
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"
  }
}
Run Code Online (Sandbox Code Playgroud)
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()
    }
  }
}
Run Code Online (Sandbox Code Playgroud)
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"
  }
}
Run Code Online (Sandbox Code Playgroud)