How to add Groovy and Spock to your Hybris extension.
My goal is to develop new features for our eCommerce solution with TDD methodology. To achieve that I want to use fancy technologies: Groovy and Spock.
Hybris uses ant, and don’t have direct support for Spock, but has for Groovy. To introduce this framework to your Hybris 5.4, please fallow those steps:
General advice, read my comments in code listing.
Prerequirements:
Make sure, you configure groovy extensions in your hybris instance. To check this, please go to hybris\config\localextensions.xml and look for two entries:
<hybrisconfig (...)>
<extensions>
(...)
<extension dir="${HYBRIS_BIN_DIR}/ext-platform-optional/ygroovy" />
<extension dir="${HYBRIS_BIN_DIR}/ext-platform-optional/groovynature" />
(...)
</extensions>
</hybrisconfig>
Step 1
Configure your extension to use maven and add groovy (EXTENSION_PATH/extensioninfo.xml):
<extensioninfo>
<extension (...) usemaven="true">
<requires-extension name="groovynature"/>
(...)
</extension>
</extensioninfo>
Step 2
This step is needed if you didn’t create extension with groovy nature.
Add missing ant macrodef, for your extension (EXTENSION_PATH/buildcallbacks.xml):
<project name="EXTENSION_NAME_buildcallbacks">
<macrodef name="EXTENSION_NAME_before_build">
<sequential>
<!-- defines native file extension used by the nature of the extension -->
<property name="ext.EXTENSION_NAME.native.file.extension" value="groovy"/>
<!-- defines source folder for groovy files -->
<property name="ext.EXTENSION_NAME.additional.src.dir" value="groovysrc"/>
<!-- defines test source folder for groovy tests -->
<property name="ext.EXTENSION_NAME.additional.testsrc.dir" value="groovytestsrc"/>
<outofdate>
<sourcefiles>
<fileset dir="${ext.EXTENSION_NAME.path}">
<include name="${ext.EXTENSION_NAME.additional.src.dir}/**"/>
</fileset>
</sourcefiles>
<targetfiles path="${HYBRIS_TEMP_DIR}/touch/EXTENSION_NAME_srctouch"/>
<sequential>
<touch mkdirs="true">
<fileset
dir="${ext.EXTENSION_NAME.path}/${ext.EXTENSION_NAME.additional.src.dir}"/>
</touch>
</sequential>
</outofdate>
<outofdate>
<sourcefiles>
<fileset dir="${ext.EXTENSION_NAME.path}">
<include name="${ext.EXTENSION_NAME.additional.testsrc.dir}/**"/>
</fileset>
</sourcefiles>
<targetfiles path="${HYBRIS_TEMP_DIR}/touch/EXTENSION_NAME_testsrctouch"/>
<sequential>
<touch mkdirs="true">
<fileset
dir="${ext.EXTENSION_NAME.path}/${ext.EXTENSION_NAME.additional.src.dir}"/>
<fileset
dir="${ext.EXTENSION_NAME.path}/${ext.EXTENSION_NAME.additional.testsrc.dir}"/>
</touch>
</sequential>
</outofdate>
</sequential>
</macrodef>
<macrodef name="EXTENSION_NAME_after_compile_core">
<sequential>
<groovynature_compile_core extname="EXTENSION_NAME"/>
</sequential>
</macrodef>
(...)
</project>
Step 3
Add required dependencies to your extension (EXTENSION_PATH/external-dependencies.xml):
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
(...)
<dependencies>
<!-- TESTING -->
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.0-groovy-2.3</version><!-- Hybris 5.4 depends on Groovy 2.3, so we are obligated to use this version -->
<scope>test</scope>
</dependency>
<!-- Optional dependencies for using Spock -->
<!-- use a specific Groovy version rather than the one specified by spock-core -->
<!-- already in hybris
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.3.1</version>
</dependency>-->
<dependency> <!-- enables mocking of classes (in addition to interfaces) -->
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.1</version>
<scope>test</scope>
</dependency>
<dependency> <!-- enables mocking of classes without default constructor (together with CGLIB) -->
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>2.1</version>
<scope>test</scope>
</dependency>
<dependency> <!-- only required if Hamcrest matchers are used -->
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>5.0.3</version><!-- watch out for this one! -->
</dependency>
</dependencies>
</project>
Run maven to update your new dependencies:
hybris\bin\platform> ant updateMavenDependencies
Maven should download all your new dependencies into EXTENSION_PATH/lib folder.
Step 4
Replace old ASM library with newer. Spock requires this change.
Replace: hybris/bin/platform/ext/core/lib/asm-3.3.1.jar with asm-5.0.3.jar.
You can find this JAR in your EXTENSION_PATH/lib folder.
Step 5
Create your firs Spock Specification in folder EXTENSION_PATH/groovytestsrc.
package pl.com.bernas.hybris.groovy
import de.hybris.bootstrap.annotations.UnitTest
import org.junit.Test
import spock.lang.Specification
/**
* IMPORTANT!
* @UnitTest is really important for Hybris to know when this test should be executed.
* Without any of de.hybris.bootstrap.annotations.* annotation, test mechanism will not pick up this specification.
*
* Created by kirkor on 7/25/2016.
*/
@UnitTest
class SimpleStringComparatorSpec extends Specification {
/**
* IMPORTANT!
* If a test class don't have at least one test annotation,
* TestClassesUtil will ommit this test and it will not be executed.
*/
@Test
def "should concatenate two strings into one"() {
given:
String test = "I have a dog"
when:
test += " and two cats."
then:
test == "I have a dog and two cats."
}
}
Testing…
hybris\bin\platform> setantenv.bat
hybris\bin\platform> cd ..\custom\EXTENSION
hybris\bin\custom\EXTENSION> ant build
(...)
build:
[echo] preparing...
[echo] building extension 'EXTENSION'...
(...)
[groovyc] Compiling 1 source files to hybris\bin\custom\EXTENSION\classes
[testClassesScanner] Found 1 EXTENSION testclasses in 14.25 ms
BUILD SUCCESSFUL
Total time: 10 seconds
hybris\bin\custom\EXTENSION> ant unittests -Dtestclasses.packages=pl.com.bernas.*
(...)
[echo] preparing...
[echo] Annotations : unittests
[echo] Extensions : EXTENSION
[echo] Packages(+) : pl.com.bernas.*
[echo] Packages(-) :
[echo] JUnit Split :
[echo] Web : false
(...)
|-- Adding Filter for package pl.com.bernas.*
|-- Adding Filter for UnitTests
|-- Adding Filter for extension EXTENSION
[yunitint] Using TestClassesUtil...
[yunitint] Found 1 filtered classes...
[yunitint] Scanning finished in : 337ms, found 1 testclasse(s)!
[yunitint] --> found 1 testclasses!
(...)
[yunitint] Running pl.com.bernas.hybris.groovy.SimpleStringComparatorSpec
[yunitint] INFO [main] (junit) [SimpleLog4jPerformanceMeasurement] Test method pl.com.bernas.hybris.groovy.SimpleStringComparatorSpec.should concatenate two strings into one succeeded. Time taken: 181.5 ms
[yunitint] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.636 sec
(...)
[echo] Report generated to src/hybris/log/junit/index.html
What we just achieve is the possibility of running together, the old JUnit tests and Spock Specification. This is because Spock is build on top of JUnit, as a Runner.
This is extremely useful if we already have some test in JUnit, but we want to add new with Spock, and run them from command line on Jenkins or Bamboo – to have one big report about our tests.