Aniket Upadhyay
Aniket Upadhyay

Reputation: 21

How to mock variables from a groovy file

I have a groovy file created under "vars" in a Jenkins-shared-lib.
Few variables are defined inside call().
I want to mock the variables in a groovy test file.

Variables are defined in sonarGradleProject.groovy in vars:

#!/usr/bin/env groovy

import static com.example.jenkins.Constants.* 

def call(Map params = [:]) {
    def sonarCredId = params.sonarCredentialId ?: SONAR_CREDENTIAL_ID_DEFAULT;
    def sonarUrl = params.sonarUrl ?: SONAR_URL;
    def profile = params.profile ?: 'example';

    withCredentials([string(credentialsId: sonarCredId, variable: 'SONAR_TOKEN')]) {
        sh "./gradlew --no-daemon jacocoTestReport sonarqube -P${profile} -Dsonar.host.url=${sonarUrl} -Dsonar.login=$SONAR_TOKEN -Dsonar.verbose=true"
    }
}

Test file looks like this:

import com.example.jenkins.testing.JenkinsPipelineSpecification

class SonarGradleProjectSpec extends JenkinsPipelineSpecification {
    def "expected minor value"() {
        setup:
            def sonarGradleProject = loadPipelineScriptForTest("vars/sonarGradleProject.groovy")
            explicitlyMockPipelineStep('withCredentials')
        when:
            def verType = sonarGradleProject(profile: 'foo')
        then:
            1 * getPipelineMock("sh")("./gradlew --no-daemon jacocoTestReport sonarqube -P${profile} -Dsonar.host.url=${sonarUrl} -Dsonar.login=$SONAR_TOKEN -Dsonar.verbose=true")
        expect:
            'foo' == profile
    }
}

On executing the test case, I get this error:

java.lang.IllegalStateException: There is no pipeline variable mock for [profile].
    1. Is the name correct?
    2. Is it a GlobalVariable extension point? If so, does the getName() method return [profile]?
    3. Is that variable normally defined by Jenkins? If so, you may need to define it by hand in your Spec.
    4. Does that variable come from a plugin? If so, is that plugin listed as a dependency in your pom.xml?
    5. If not, you may need to call explicitlyMockPipelineVariable("profile") during your test setup.

    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at com.example.jenkins.testing.JenkinsPipelineSpecification.addPipelineMocksToObjects_closure1$_closure15(JenkinsPipelineSpecification.groovy:755)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at SonarGradleProjectSpec.expected minor value(sonarGradleProjectSpec.groovy:12)
Caused by: groovy.lang.MissingPropertyException: No such property: (intercepted on instance [SonarGradleProjectSpec@3dfb1626] during test [SonarGradleProjectSpec@3dfb1626]) profile for class: SonarGradleProjectSpec
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at com.example.jenkins.testing.JenkinsPipelineSpecification.addPipelineMocksToObjects_closure1$_closure15(JenkinsPipelineSpecification.groovy:754)
    ... 3 more

I want to use the variables in test. How do I mock them?

Upvotes: 2

Views: 899

Answers (1)

user17544628
user17544628

Reputation:

I've run into similar issues before. The issue for me is that I was trying to verify the interactions of a mock that uses string interpolation. So for the one entry in the then section...

1 * getPipelineMock("sh")("./gradlew --no-daemon jacocoTestReport sonarqube -P${profile} -Dsonar.host.url=${sonarUrl} -Dsonar.login=$SONAR_TOKEN -Dsonar.verbose=true")

I would define the profile and sonarUrl variables in the setup section (i.e., def profile = 'test123'), referenced to verify the mocked sh step interaction. I believe you would also want to adjust the assignment of default values to use the null-safe ?. operator to access key-value pairs in the params map. So def sonarUrl = params.sonarUrl ?: SONAR_URL; would become def sonarUrl = params?.sonarUrl ?: SONAR_URL;


You may have already addressed this and omitted it from the question, but I figured I'd share this information too. Please ignore the following information if you've already addressed it. :)

The three environment variables defined in the script - SONAR_CREDENTIAL_ID_DEFAULT, SONAR_URL, and SONAR_TOKEN - will need to be injected into the script before calling sonarGradleProject. That should be sufficient to test default values if key-value pairs are not provided in the params map.

setup:
    def sonarGradleProject = loadPipelineScriptForTest("vars/sonarGradleProject.groovy")
    explicitlyMockPipelineStep('withCredentials')

    // Inject environment variables. 
    // First argument is the variable name and second argument is the variable value.
    sonarGradleProject.getBinding().setVariable('SONAR_CREDENTIAL_ID_DEFAULT', 'test123')
    sonarGradleProject.getBinding().setVariable('SONAR_URL', 'test123')
    sonarGradleProject.getBinding().setVariable('SONAR_TOKEN', 'test123')

Upvotes: 0

Related Questions