Untitled

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.

Today I faced small confusion how to configure my Eclipse to use JRebel with Grails 3 framework. This is step by step configuration.

  1. Get ready with your eclipse on fedora 22 and gnome shell (I’m using sts-3.7.0.RELEASE);
  2. Install Gradle IDE Plugin;
    Screenshot from 2015-09-30 10-25-49
  3. Install JRebel – it’s just a tool to autoreloading classes and spring beans ;-);
    Screenshot from 2015-10-02 10-49-40
  4. Install Groovy 2.4 support from GitHub, (eclipse 4.5 Mars);
    Screenshot from 2015-10-02 10-43-57
  5. Create your Grails 3 application
    grails create-app hello-world --profile=web
    cd hello-world
    grails
    grails> create-controller homePage
  6. Import project into eclipse;
  7. Edit gradle.build file (to add JRebel compatibility), documentation at GitHub:
    buildscript {
      repositories {
         ...
         mavenCentral()
      }
    
      dependencies {
         ...
         classpath group: 'org.zeroturnaround', name: 'gradle-jrebel-plugin', version: '1.1.2'
      }
    }
    ...
    apply plugin: 'rebel'
    ...
    build.dependsOn(generateRebel)
    
  8. Run “gradle generateRebel” -> generate rebel.xml file
    1. In eclipse, Window -> Show view -> Other -> Select Gradle -> Gradle Tasks
      Screenshot from 2015-10-02 15-06-47
    2. The file is generated under this location: build/classes/main/rebel.xml

During the next few days I will publish how to run Grails 3 with JRebel:

  1. From command line without JRebel
  2. From command line with JRebel
  3. From eclipse as a Spring Boot Application without JRebel
  4. From eclipse as a Spring Boot Application with JRebel