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()