lolotron lolotron - 2 months ago 19
Groovy Question

Use same classloader for JUnit and Cucumber

I have a cucumber test that runs with

@RunWith(Cucumber)
. The test uses static field from an other class. It looks like:

Cucumber test

@RunWith(Cucumber)
@CucumberOptions(
features = 'src/test/resources/features/cucumber-test.feature',
glue = ['src/test/groovy']
)
class CucumberTest {
@BeforeClass
static void setUp() {
StaticClass.filed
}
}


Static class

class StaticClass {
static {
filed = UUID.randomUUID().toString()
println "Field initialized with value $filed in ${this.classLoader.toString()}\n"
}
static String filed
}


The
cucumber-test.feature
only contains line
Feature: None
and there are no step definitions. When I run this test, the output is

Field initialized with value 649b6d18-fe5a-4993-a92e-74645c3ab07d in groovy.lang.GroovyClassLoader$InnerLoader@534a5a98
Field initialized with value 9639e4de-661f-4ac7-afc9-715cdd17bb35 in sun.misc.Launcher$AppClassLoader@4e25154f


So static block was executed two times, but with different classloaders. It looks like there's one classloader for JUnit and the other one for Cucumber runner.

Also, if I comment out the line
StaticClass.filed
in
setUp
method the static block is only executed once. This time only with Groovy classloader

Field initialized with value 73d1d302-826c-4ec3-a9db-c065b399487f in groovy.lang.GroovyClassLoader$InnerLoader@5a45133e


The dependencies that I have in my project are:

dependencies {
compile 'info.cukes:cucumber-groovy:1.2.5'
compile 'info.cukes:cucumber-junit:1.2.5'
compile 'org.codehaus.groovy:groovy-all:2.4.12'
}


Is there a way to use the same class loader for both JUnit and Cucumber runner?

Answer Source

Take a look at your CucumberOptions:

glue = ['src/test/groovy']

This statement results in spawning a separate Groovy class loader to get classes (and thus recompile them) directly from specified source folder

All you need is to instruct Cucumber to take Groovy step definitions from classpath instead

glue = ['classpath:your.step.definitions.package.name']

Or even simplier:

glue = ['classpath:'] 

- if you dont want to care about package names at all. But note that last one may not be acceptable at many cases, as it will trigger scan/load of all the available classpath, so sticking with the precise package name(s) for step definitions is generally preferred