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.