mocking custom steps in jenkins vars files

681 Views Asked by At

In my Jenkins shared library, I have tons of groovy files in the /vars dir that define custom steps.

Many of them have multiple methods defined, and one method in a file may call another in the same file.

I am looking for a way to mock these local methods, so I can unit test each method, specifically those that call the others, without actually invoking them.

Say the structure is like this:

// vars/step.groovy

def method1() {
  def someVar
  
  result = method2(someVar)

  if (result) { 
    echo 'ok' 
  }
  else { 
    echo 'no' 
  }

}

def method2(value) {

  if (value == 1) { 
    return true 
  }
  else { 
    return false 
  }

}

Obviously this is a very simplified example. But what I need is a way to mock method2 so that I can test method1 with result of both true and false, without actually invoking method2.

I have tried the helper.registerAllowedMethod pattern, but that doesn't seem to apply to local methods. I've tried Mockito and Spock but they seem like overkill for what I need, and too much change to inject for simple cases. I've also tried defining the methods locally in the test script with mock closures, but I can't find the right place to do that and/or the correct syntax.

I hope there's a way to do something like this:

// test/com/myOrg/stepTest.groovy
import org.junit.*
import com.lesfurets.jenkins.unit.*
import com.lesfurets.jenkins.unit.BasePipelineTest
import static groovy.test.GroovyAssert.*

class stepTest extends BasePipelineTest {
  def step

  @Before
  void setUp() {
    super.setUp()
    step = loadScript("vars/step.groovy")
  }

  @Test
  void method1Test_true () {
    helper.registerAllowedMethod('method2', [], { true }

    result = step.method1()

    assert 'ok' == result
  }

  @Test
  void method1Test_false () {
    helper.registerAllowedMethod('method2', [], { false }

    result = step.method1()

    assert 'no' == result
  }
}

UPDATE: one thing i've recently noticed is, in the stacktrace, the method2 local function is not listed. It's as if the local function is instantiated "inline" or in some way that it is not actually a new call, the execution just flows into it. I don't know the technical term. But it explains why the mock of method2 never gets hit: it is never called.

 method1.call()
      method1.successfullyMockedExternalFunction()
      // i would expect method2 to be here, but it's not - the next stack items are functions _inside_ method2.
      method1.functionInsideMethod2()

UPDATE 2: This got some attention in the JPU GitHub repo.

0

There are 0 best solutions below