JenkinsPipelineUnit icon indicating copy to clipboard operation
JenkinsPipelineUnit copied to clipboard

groovy.lang.MissingPropertyException: No such property: b for class: a

Open kerby82 opened this issue 4 years ago • 5 comments

I'm trying to test a groovy file that referentiate a class on another groovy file

vars/a.groovy

def runMigrations {
 if (b.getBoolean('xxxx)) {
  return true
 }
}

If I create a test like:

class ATests extends BasePipelineTest {
 void setUp() throws Exception[
  super.setUp()
  def a = loadScript('vars/a.groovy')
 }

@Test
 void runMig() {
  a.runMigrations()
  printCallStack()
 }
}

I got an error saying: groovy.lang.MissingPropertyException: No such property: b for class: a

kerby82 avatar Nov 11 '20 16:11 kerby82

The error seems legit. Where does b come from anyways? I suspect you need to share a bit more context of a.groovy.

nre-ableton avatar Nov 11 '20 17:11 nre-ableton

both a.groovy and b.groovy are located in vars This is my build.gradle.kts



plugins {
  id("com.mkobit.jenkins.pipelines.shared-library") version "0.10.1"
  id("com.github.ben-manes.versions") version "0.21.0"
  java
}

java {
  sourceCompatibility = JavaVersion.VERSION_1_8
  targetCompatibility = JavaVersion.VERSION_1_8
}

tasks.withType<Test> {
  this.testLogging {
    this.showStandardStreams = true
  }
}

val log4jVersion = "2.11.2"
val slf4jVersion = "1.7.26"
val declarativePluginsVersion = "1.3.9"


dependencies {
  // logging stuffs
  testImplementation("org.slf4j:slf4j-api:$slf4jVersion")
  testImplementation("org.apache.logging.log4j:log4j-api:$log4jVersion")
  testImplementation("org.apache.logging.log4j:log4j-core:$log4jVersion")
  testImplementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion")
  testImplementation("org.apache.logging.log4j:log4j-jul:$log4jVersion")

  // general testing stuff
  testImplementation("org.assertj:assertj-core:3.4.1")
  testImplementation("com.lesfurets:jenkins-pipeline-unit:1.8")
  testImplementation("com.cloudbees:groovy-cps:1.12")
  testImplementation("junit:junit:4.12") // TODO: update to 5

  // jenkins specific deps
  testImplementation("org.jenkins-ci.plugins:pipeline-build-step:2.10")
  testImplementation("org.jenkinsci.plugins:pipeline-model-api:$declarativePluginsVersion")
  testImplementation("org.jenkinsci.plugins:pipeline-model-declarative-agent:1.1.1")
  testImplementation("org.jenkinsci.plugins:pipeline-model-definition:$declarativePluginsVersion")
  testImplementation("org.jenkinsci.plugins:pipeline-model-extensions:$declarativePluginsVersion")
  testImplementation("org.jenkins-ci.plugins.workflow:workflow-cps-global-lib:2.8")
}

jenkinsIntegration {
  baseUrl.set(uri("http://localhost:5050").toURL())
  authentication.set(providers.provider { com.mkobit.jenkins.pipelines.http.AnonymousAuthentication })
  downloadDirectory.set(layout.projectDirectory.dir("jenkinsResources"))
}

sharedLibrary {
  coreVersion.set(jenkinsIntegration.downloadDirectory.file("core-version.txt").map { it.asFile.readText().trim() })
  pluginDependencies {
    dependency("org.jenkins-ci.plugins", "pipeline-build-step", "2.10")
    dependency("org.jenkinsci.plugins", "pipeline-model-api", declarativePluginsVersion)
    dependency("org.jenkinsci.plugins", "pipeline-model-declarative-agent", "1.1.1")
    dependency("org.jenkinsci.plugins", "pipeline-model-definition", declarativePluginsVersion)
    dependency("org.jenkinsci.plugins", "pipeline-model-extensions", declarativePluginsVersion)
    dependency("com.lesfurets","jenkins-pipeline-unit","1.8")
  }
}

I'm testing the framework so b.groovy is just

def getBoolean(String input) {
 return true
}

How do the test framework should load implicitly the b class?

kerby82 avatar Nov 11 '20 17:11 kerby82

The main issue here how can a groovy file referentiating a method from another groovy file be tested?

kerby82 avatar Nov 11 '20 20:11 kerby82

Ah, ok, I see what you mean now. So first of all, your build.gradle file doesn't matter, at least when Jenkins is concerned. Instead, you'll need to create a new instance of b and attach it to the script instance in your test cases, like so:

class ATests extends BasePipelineTest {
  Object a
  Object b

  @Override
  @Before
  void setUp() {
    super.setUp()
    this.a = loadScript('vars/a.groovy')
    this.b = loadScript('vars/b.groovy')
  }

  @Test
  void runMig() {
    a.b = this.b
    a.runMigrations()
    printCallStack()
  }
}

nre-ableton avatar Nov 12 '20 11:11 nre-ableton

Thanks @nre-ableton: That helped me a lot!

reinholdfuereder avatar Feb 26 '21 09:02 reinholdfuereder