How to test your Grails application




gr8conf.us 2014

Original Title 


How to test the $%# out of your grails app

whoami



Colin Harrington
Principal Consultant
Object Partners Inc



@ColinHarrington
colin.harrington@objectpartners.com

Basics


http://grails.org/doc/latest/guide/testing.html


grails test-app 

-------------------------------------------------------
Running Unit Tests…
Running test FooTests...FAILURE
Unit Tests Completed in 464ms …
-------------------------------------------------------
Tests failed: 0 errors, 1 failures 

Targeting


grails test-app SimpleController 
grails test-app *Controller 
grails test-app some.org.*Controller 
grails test-app some.org.* 
grails test-app some.org.**.* 
grails test-app SimpleController.testLogin 
grails test-app some.org.* SimpleController.testLogin BookController 

Phase:Type


grails test-app unit: 

grails test-app :spock 

grails test-app phase:type

grails test-app functional:spock 

Phases

  • unit
  • integration
  • functional
  • custom


Support to create your own Phases!!

Framework


  • Services 
  • Controllers
  • Filters
  • Domains
  • Constraints
  • Command objects
  • Codecs 
  • Configs
  • GSP
  • UrlMappings
  • WebFlow

Test mixins

grails.test.mixin.TestFor 
grails.test.mixin.Mock 
grails.test.mixin.TestMixin 
grails.test.mixin.support.GrailsUnitTestMixin 
grails.test.mixin.domain.DomainClassUnitTestMixin 
grails.test.mixin.services.ServiceUnitTestMixin 
grails.test.mixin.web.ControllerUnitTestMixin 
grails.test.mixin.web.FiltersUnitTestMixin 
grails.test.mixin.web.GroovyPageUnitTestMixin 
grails.test.mixin.web.UrlMappingsUnitTestMixin 
grails.test.mixin.hibernate.HibernateTestMixin 

GrailsUnitTestCase



@Deprecated

Example Controller Test


import grails.test.mixin.TestFor
import spock.lang.Specification
@TestFor(SimpleController)
class SimpleControllerSpec extends Specification {

    void "test hello"() {
        when:
        controller.hello()

        then:
        response.text == 'hello'
    }
} 

model

UrlMappings

static mappings = {
    "/actionOne"(controller: "simple", action: "action1")
    "/actionTwo"(controller: "simple", action: "action2")
} 
import com.demo.SimpleController
import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(UrlMappings)
@Mock(SimpleController)
class UrlMappingsSpec extends Specification {

    void "test forward mappings"() {
        expect:
        assertForwardUrlMapping("/actionOne", controller: 'simple', action: "action1")
        assertForwardUrlMapping("/actionTwo", controller: 'simple', action: "action2")
    }
} 

@Mock


Real in-memory GORM database (unit tests)

@Mock(Book) 

Magic

no SQL support  
(GORM API not GORM Hibernate)

Spock Data Driven

http://spock-framework.readthedocs.org/en/latest/data_driven_testing.html

class Math extends Specification {
    def "maximum of two numbers"(int a, int b, int c) {
        expect:
        Math.max(a, b) == c

        where:
        a | b | c
        1 | 3 | 3
        7 | 4 | 4
        0 | 0 | 0
    }
} 

Hierarchy




GrailsUnitTestMixin


static GrailsWebApplicationContext applicationContext
static GrailsWebApplicationContext mainContext
static GrailsApplication grailsApplication
static ConfigObject config
static MessageSource messageSource
Map validationErrorsMap = new IdentityHashMap()
Set loadedCodecs = [] 

ControllerUnitTestMixin

  • webRequest
  • request
  • response
  • servletContext
  • groovyPages
  • views
  • session
  • params
  • view
  • model
  • flash

  • sets up codecs

GroovyPageUnitTestMixin

UrlMappingsUnitTestMixin


Perspectives

Unit Testing


No IO in Unit tests!

Unit tests just test your unit! 
Mocks/Spies/Stubs


Unit being tested:
Class, Hierarchy, MethodLevel.

Integration Testing


integration of Spring components

Real Database
Spring Container bootstrapped
Transaction wrapper
No HTTP connector.

Functional Testing


Test the whole Application

From the outside
All the layers are there.

As a user would

Browser, API, etc.

Stubs


service.metaClass.myMethod = {
    //does nothing    //we don't care if it was called or not
} 

Spies


Spy on the input ..

service.metaClass.someMethod = { input ->
    assert input == "expected"
} 

Mocks



Mocks
Spies
Stubs

Mocks


  • GrailsMock and mockFor 
  • in the GrailsUnitTestMixin

  • Groovy's MockFor (Capital M)

  • Spock's Interactions Mock()


MetaClass Magic

Additional Perspectives

Smoke tests
performance testing
security (pen) testing
3rd party
Prod testing/monitoring.
Continuous Integration
Occasional Integration
Cluster testing

Tools


IDE
Jenkins
GROM
Quick feedback
Script to open test-reports.

Plugins


Plugin Portal

Test build scope

test ':fixtures:1.3' 

Build Scope



BuildConfig.groovy
plugins { test ':fixtures:1.3' }

Data Generator/helper

Code Coverage/Quality

Running tests

Testing Frameworks

Functional Tests


JavaScript 


Tools

Title

Know your tools
Test from different angles
Practice Practice Practice
Build your own tools

Thank you




@ColinHarrington

How to test your Grails application

By Colin Harrington

How to test your Grails application

  • 4,725