JenkinsPipelineUnit
JenkinsPipelineUnit copied to clipboard
Feature request: mock global var methods
Please add the ability to mock methods of global vars with registerMethod. For example, given vars/foo.groovy:
def call() { ... }
def bar() { ... }
Provide a way to mock foo.bar().
Hi, Have you a solution for this issue ?
Thank's
Actually,
You can mock bar
, but only if it the calling scope is within a different file. (using registerAllowedMethod('bar',[], null)
.
It doesn't work when you call the function within the same file as they are contained within the same class and the metaClass.invokeMethod
nor the metaClass.static.invokeMethod
functions are called when calling a different function from the same class. (I think it might be related to initializing PogoMetaMethodSite vs PogoMetaClassSite somewhere deep in the groovy core)
I have no clue how to fix this, but it would be very nice to be able to mock these functions.
Thanks
You can use an Expando as a workaround for this. Something like any of these:
binding.setVariable('bar', new Expando (foo: "foo result")
binding.setVariable('bar', new Expando (foo: "foo result", baz: "baz result")
binding.setVariable('bar', new Expando (foo: { return calculate_foo_result () })
etc.
I think my explanation might have been a bit confusing, I'll retry to explain with an example:
scriptA.groovy
call(Map args) {
print()
}
void print() {
echo('hello')
}
scriptB.groovy
call(Map args) {
scriptA.echo('hello')
}
When testing scriptB
, I'm doing something of the sort, and I am able to successfully mock print
binding.setVariable('scriptA', loadScript('vars/scriptA.groovy'))
helper.registerAllowedMethod('print', []) { -> } // <- mock gets called successfully
loadScript('vars/scriptB.groovy').call()
But, when testing scriptA
, it is not possible to mock print
helper.registerAllowedMethod('print', []) { -> } // <- mock never gets called
loadScript('vars/scriptA.groovy').call()
Duplicates #51 #142 #141
helper.registerAllowedMethod('print', []) { -> } // <- mock never gets called
Try
helper.registerAllowedMethod('print', [], { null })
I mocked a lot of global methods and worked pretty nicely. I tested the above approach and worked as aspected. You can even add some codes in the null
section and put breakpoints into it to verify.
helper.registerAllowedMethod('print', [], {
println 'Put a breakpoint here and see it breaks.'
})
I'm trying to make something like this work, but without success so far... I have a shared library with several vars/*****.groovy
files exposing different functions. I'm using them from my Jenkinsfile using xxxxx.function(...)
and yyyyy.function(...)
where xxxxx
and yyyyy
are the names of those vars/*****.groovy
files.
I need to mock all the functions in one of the *****.groovy
files as they are making calls to externals systems that are not available while testing. Something like helper.registerAllowedMethod('xxxxx.function', ....)
would be perfect, but it doesn¡t work, and I'm not able to find an alternative using other mocking frameworks as I don't know how to refer to the class I need to mock.
Any hint would be appreciated. Thanks!
helper.registerAllowedMethod('xxxxx.function', ....)
won't work because it only registers a single top level method. For your use case, you must mock the class xxxxx
.
You can then set class xxxxx
as property xxxxx
so your shared library can use them in the tests as xxxxx.function()
calls.
binding.setProperty('xxxxx', new xxxxx())
An example of a mocked class:
package mock // up to you
class PipelineHelper implements Serializable {
public void requiredParameterCheck(def paramName, def paramValue, def errorMessage = '') {
if (errorMessage == '') {
errorMessage = "--- SHARED LIBRARY ERROR: Missing required parameter ${paramName} ---"
}
if ((paramValue == null) || (paramValue == '')) {
throw new Exception(errorMessage)
}
}
}
This mocked class is a partial copy of my pipelineHelper.groovy
. The requiredParameterCheck()
method is commonly used in other shared pipeline libraries. Notice that i do not mock def call() {...}
of pipelineHelper.groovy
because it is not in the scope for mocking.
Depending on the complexity of the method. If you use steps like echo
in the method above, you need to register echo
in your test file with:
helper.registerAllowedMethod('echo', [String.class], {
null // or do something with it
})
My shared pipeline library is unfortunately not open source yet, but I work towards open sourcing it. Hope that helps.