Integration Testing with Gradle, Selenium and Spock for Java project

This article was inspired by Tutorial: Integration Testing with Selenium – Part 1 where author, Alex Collins was using Maven and jUnit. I like Gradle and Groovy as a more convenient alternative to maven and jUnit for building and testing. I usually write my production code in java but test with groovy and spock framework. I found it to be a very efficient and productive combination.
I will cover those steps:

  • Setting up a web project using gradle, and then create integration tests with Spock and Selenium
  • Setting up embedded tomcat server and deploy application to it
  • Run integration test with Firefox browser driven by Selenium web driver
  • Later we will look into good ways to model the pages in your site using “page objects” and Geb framework
  • Use groovy to perform CRUD operations on a database before starting integration test
  • Incorporate performance measurements into the tests

This setup works for Java project, giving development teams modern language (Groovy) and Behavior-Driven Development (BDD) frameworks (Spock) to write tests.

Requirements:
Installed latest releases of groovy and gradle. My setup is groovy 1.8.3 and gradle 1.0-rc-2
1. Create a Web Application

Gradle does not have a simple task to create structure for web application, like maven does. Instead, we will be using gradle-template plugin.
Plugin installation:

    install Bazaar VCS (Current version is 2.3.3)
    Branch the project via the following command:
    bzr branch lp:gradle-templates
    Build the plugin:
    cd gradle-templates
    gradle build

    Modify the apply script (tpInstallDir line ) that is found under the installation directory.
    buildscript {
    	repositories {
    		ivy {
    		   String tpInstallDir = 'file:///Users/edvorkin/IdeaProjects/gradle-templates'
    			templatesname = 'gradle_templates'
    			artifactPattern "${tpInstallDir}/build/libs/[artifact]-[revision].jar"
    		}
    	}
    	dependencies {
    		classpath 'gradle-templates:templates:1.2'
    	}
    }
    // Check to make sure templates.TemplatesPlugin isn't already added.
    if (!project.plugins.findPlugin(templates.TemplatesPlugin)) {
    	project.apply(plugin: templates.TemplatesPlugin)
    }
    

    Create a build.gradle file and apply this plugin
    apply from: 'file:///Users/edvorkin/IdeaProjects/gradle-templates/installation/apply-local.groovy'
    execute gradle tasks to get a list of tasks and then
    gradle createWebappProject

    This will create a new web application project with gradle/ maven default structure.
    Create a simple index.html page with title tag Hello World

    Configuring embedded Tomcat Server
    For this we will use gradle-tomcat plugin.
    If you want to work with locally or remotely installed Tomcat, Jetty or Glassfish containers, then you should use gradle-cargo plugin instead. I have configured both of them.

    Change directory into your new web application.
    Create a new build.gradle file. At this point I would suggest to import the web application project into IDE to make more productive environment. IntelliJ and NetBeans support gradle projects.
    We can set-up gradle to start a Tomcat container prior to running the tests, and then stop it afterwards. This will allow us to start our site, run the integration tests, and then stop it afterwards. For running the integration tests you will want to run the Tomcat task as daemon thread and shut it down once your tests are done. The following example demonstrates how to set up a Gradle task that provides this functionality. Of course this is only one way of doing it.

    test {
        maxParallelForks = 5
        forkEvery = 50
        include '**/Test*.*'
    }
    
    task integrationTest(type: Test, dependsOn: "test") << {
       include '**/IntegrationTest*.*'
    }
    
    
    integrationTest.doFirst {
        println 'Starting the embedded tomcat server'
        tasks.tomcatRun.daemon=true
        tasks.tomcatRun.execute()
    
    }
    
    
    integrationTest.doLast {
        println 'Stopping the embedded tomcat server'
        tasks.tomcatStop.execute()
    }

    Creating Integration Test with Spock and Selenium Web Driver.
    Spock, as the homepage states, is a “testing and specification framework for Java and Groovy applications.” In a sea of similar tools, it distinguishes itself from the others by a very expressive DSL that reads nearly like natural English writing.

    Adding dependencies for Spock and Selenium Web Driver:

    def gebVersion = "0.7.0"
        def seleniumVersion = "2.21.0"
        // If using Spock, need to depend on geb-spock
        testCompile "org.codehaus.geb:geb-spock:$gebVersion"
    
        // Need a driver implementation
            testCompile "org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion"
            testRuntime "org.seleniumhq.selenium:selenium-support:$seleniumVersion"
         
        // spock 
         testCompile 'org.codehaus.groovy:groovy-all:1.8.3'
         testCompile(group:'org.spockframework',name:'spock-core',version:'0.6-groovy-1.8')
        testCompile 'junit:junit:4.8.2'

    If you use intelliJ, you have to reimport the project, so this IDE can build dependencies correctly. Hopefully this bug will be fixed soon by JetBrain.
    Integration test:
    import spock.lang.Specification
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.firefox.FirefoxDriver;
    
    
    class HomePageIT extends Specification {
        def "testing home page" () {
            def url
            WebDriver drv
        given: "Open home page"
            url = 'http://localhost:8080/selenium-test'
            drv = new FirefoxDriver();
    
    
        when: "page loaded"
            drv.get(url);
    
        then: "title should be 'Hello word'"
            assert drv.getTitle()=='Hello World'
            drv.close()
    }
    }

    At this point you should be able to run your integration tests:

    gradle  integrationTest
    :compileJava UP-TO-DATE
    :compileGroovy UP-TO-DATE
    :processResources UP-TO-DATE
    :classes UP-TO-DATE
    :compileTestJava UP-TO-DATE
    :compileTestGroovy
    :processTestResources UP-TO-DATE
    :testClasses
    :test
    :integrationTest
    Starting the embedded tomcat server
    Started Tomcat Server
    The Server is running at http://localhost:8080/selenium-test
    Stopping the embedded tomcat server
    
    BUILD SUCCESSFUL
    

    You should see Firefox is started and web page is loaded.
    Complete build.gradle script.
    apply plugin: 'cargo'
    apply plugin:  'tomcat'
    apply plugin:'groovy'
    apply plugin: 'java'
    
    
    group = 'selenium-test'
    
    
    repositories {
        mavenCentral()
    }
    
    buildscript {
        repositories {
            add(new org.apache.ivy.plugins.resolver.URLResolver()) {
                name = 'GitHub'
                addArtifactPattern 'http://cloud.github.com/downloads
                                      /[organisation]/[module]/[module]-[revision].[ext]'
            }
            maven { url 'http://repository.codehaus.org' }
           	maven { url 'http://snapshots.repository.codehaus.org' }
           	ivy { url "http://repository.codehaus.org" }
        }
    
        dependencies {
            classpath 'bmuschko:gradle-cargo-plugin:0.5.2'
            classpath 'bmuschko:gradle-tomcat-plugin:0.9.1'
        }
    }
    
    cargo {
    	containerId = 'tomcat6x'
    	port = 8080
    	context = 'mycontext'
    	remote {
    		hostname = 'localhost'
    		username = 'tomcat'
    		password = 'tomcat'
    	}
    }
    
    
    
    dependencies {
        groovy localGroovy()
        testCompile localGroovy()
    
        def gebVersion = "0.7.0"
        def seleniumVersion = "2.21.0"
        // If using Spock, need to depend on geb-spock
        testCompile "org.codehaus.geb:geb-spock:$gebVersion"
    
        // Need a driver implementation
            testCompile "org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion"
            testRuntime "org.seleniumhq.selenium:selenium-support:$seleniumVersion"
    
    
        def cargoVersion = '1.2.1'
    
        cargo "org.codehaus.cargo:cargo-core-uberjar:$cargoVersion",
             "org.codehaus.cargo:cargo-ant:$cargoVersion"
              'jaxen:jaxen:1.1.1'
    
        def tomcatVersion = '7.0.11'
            tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
                   "org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}"
            tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") {
                exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj'
            }
    
        testCompile 'org.codehaus.groovy:groovy-all:1.8.3'
        testCompile(group:'org.spockframework',name:'spock-core',version:'0.6-groovy-1.8')
    
        testCompile 'junit:junit:4.8.2'
    }
    
    test {
        maxParallelForks = 5
        forkEvery = 5
        include '**/Test*.*'
        systemProperties "geb.build.reportsDir": "$reportsDir/geb"
        exclude '**/*IT.*'
    }
    
    [tomcatRun, tomcatStop]*.stopPort = 8081
    [tomcatRun, tomcatStop]*.stopKey = 'stopKey'
    task integrationTest(type: Test, dependsOn: "test") << {
    
    
       include '**/*IT.*'
    }
    
    
    integrationTest.doFirst {
        println 'Starting the embedded tomcat server'
        tasks.tomcatRun.daemon=true
        tasks.tomcatRun.execute()
    
    }
    
    
    integrationTest.doLast {
        println 'Stopping the embedded tomcat server'
        tasks.tomcatStop.execute()
    }
    

    In next part we will explore how to make this type of test easy to maintain and change.
    User interface changes very quickly, and we want to have framework that make it easy for us to maintain. One option is to use PageObjects pattern, as described on Selenium web site. In true groovy fashion, I will explore Geb option instead.

Submit a Comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>