+ All Categories
Home > Technology > Grails build-test-data Plugin

Grails build-test-data Plugin

Date post: 13-Jul-2015
Category:
Upload: ted-naleid
View: 6,192 times
Download: 7 times
Share this document with a friend
Popular Tags:
45
grails build-test-data plugin created by Ted Naleid and Joe Hoover Tuesday, July 14, 2009
Transcript

grailsbuild-test-data

plugin

created by Ted Naleid and Joe Hoover

Tuesday, July 14, 2009

creating test data with groovy is easy!

Tuesday, July 14, 2009

["Alice", "Bob", "Carol", "Dave"].each { new Author(name: it).save()}

iterators

closures

syntactic sugar

Tuesday, July 14, 2009

modeling your domain in grails is easy!

Tuesday, July 14, 2009

class Book { String title static belongsTo = [author: Author]}

class Author { String name static hasMany = [books: Book]}

a book belongs to an author

an author has many books

Tuesday, July 14, 2009

class User { String login

String password String email Date birthDate

static constraints = { login(size: 5..15, blank: false, unique: true)

password(size: 5..15, blank: false) email(email: true, blank: false) birthDate(max: new Date()) } }

constraints

Tuesday, July 14, 2009

def user = new User(login: “tnaleid”, password: “sekrit1”, birthDate: new Date() - (365 * 36)

).save()

test data must pass constraints

Tuesday, July 14, 2009

def user = new User(login: “tnaleid”, password: “sekrit1”, email: “[email protected]”,age: new Date() - (365 * 36)

).save()

whoops! missed an attribute!

Tuesday, July 14, 2009

def user = new User(login: “tnaleid”, password: “sekrit”, email: “[email protected]”,birthDate: new Date() - (365 * 36)

).save()

// service looks up user in DB by username and deletes itassertTrue userService.deleteByUsername(“tnaleid”)

constrained attributes are required even if your test doesn’t care about

them

Tuesday, July 14, 2009

problem multiplied by complex domain models

Tuesday, July 14, 2009

agile + code coverage = lots of tests

Tuesday, July 14, 2009

you need to add a new constraint...

what happens to all the tests?

Tuesday, July 14, 2009

Tuesday, July 14, 2009

creating maintainable test data is hard!

Tuesday, July 14, 2009

existing test datacreation strategies

Tuesday, July 14, 2009

copy/paste/modify for every

test method

void testTenDollarPurchase() { def author = new Author( name: “David Foster Wallace” ).save() Book book = new Book( author: author,

title: "The Pale King", published: new Date(), price: 10.00 as BigDecimal

).save()  def ord = service.orderBook(book.id)  //... test assertions}

void testTwentyDollarPurchase() { def author = new Author( name: “David Foster Wallace” ).save() Book book = new Book( author: author,

title: "Infinite Jest", published: new Date(), price: 20.00 as BigDecimal

).save()  def ord = service.orderBook(book.id)  //... test assertions}

Tuesday, July 14, 2009

def author

void setUp() { author = new Author( name: “David Foster Wallace” ).save()}

void testTenDollarPurchase() { Book book = new Book( author: author, title: "The Pale King", published: new Date(), price: 10.00 as BigDecimal ).save()  def order = service.orderBook(book.id)  //... test assertions}

void testTwentyDollarPurchase() { Book book = new Book( author: author, title: "Infinite Jest", published: new Date(), price: 20.00 as BigDecimal ).save()  def result = service.orderBook(book.id)  //... test assertions}

use setUp method to share objects

across tests

Tuesday, July 14, 2009

class AuthorObjectMother { static dfw() { return new Author( name: “David Foster Wallace” ).save() }}

class BookObjectMother { static thePaleKing() { return new Book( author: AuthorObjectMother.dfw(), title: “The Pale King”, published: new Date(), price: 10.00 as BigDecimal ).save() } static infiniteJest() { return new Book( author: AuthorObjectMother.dfw(), title: “Infinite Jest”, published: new Date(), price: 20.00 as BigDecimal ).save() }}

testTenDollarPurchase() {  Book book = BookObjectMother.thePaleKing() def result = service.orderBook(book.id)  //... test assertions}

void testTwentyDollarPurchase() { Book book = BookObjectMother.infiniteJest()  def result = service.orderBook(book.id)  //... test assertions}

object mother pattern

Tuesday, July 14, 2009

// fixtures/dfwBooks.groovy:fixture { davidFosterWallace(Author) { name = “David Foster Wallace” } thePaleKing(Book) { author = davidFosterWallace title = "The Pale King" published = new Date() price = 10.00 as BigDecimal } infiniteJest(Book) { author = davidFosterWallace title = "Infinite Jest" published = new Date() price = 20.00 as BigDecimal }}

// test class ...def fixtureLoadervoid testTenDollarPurchase() { fixtureLoader.load("dfwBooks") Book book = Book.findByTitle(“The Pale King”)

def result = service.orderBook(book.id)  //... test assertions}

void testTenDollarPurchase() { fixtureLoader.load("dfwBooks") Book book = Book.findByTitle(“Infinite Jest”) def result = service.orderBook(book.id)  //... test assertions}

builder DSL / test fixtures

Tuesday, July 14, 2009

all of these strategies strive to DRY up your test data

creation

Tuesday, July 14, 2009

but all of them repeat the same rules specified in the constraints

Tuesday, July 14, 2009

void testTenDollarPurchase() { Book book = new Book( price: 10.00 as BigDecimal ) mockDomain(Book, [book])

def order = service.orderBook(book.id) //...test assertions}

void testTwentyDollarPurchase() { Book book = new Book( price: 20.00 as BigDecimal ) mockDomain(Book, [book])  def result = service.orderBook(book)  //... test assertions}

grails does have mocks ... but what

are they really testing?

Tuesday, July 14, 2009

void testPurchaseBookService() { def author = new Author(

name: "First Last", ).save()

Book book = new Book(author: author, title: "title", published: new Date(), price: 10.00 as BigDecimal

).save()  def order = service.orderBook(book.id) //... test assertions}

what if we could turn this

void testPurchaseBookService() {Book book = Book.build( price: 10.00 as BigDecimal)

def result = service.orderBook(book)//... test assertions

}

into this

Tuesday, July 14, 2009

you can with the build-test-data plugin

Tuesday, July 14, 2009

build-test-data advantages

Tuesday, July 14, 2009

testing data documents what’s being tested

Tuesday, July 14, 2009

only specify values the test uses

Tuesday, July 14, 2009

test coupling is eliminated

Tuesday, July 14, 2009

you’re executing real GORM code paths

Tuesday, July 14, 2009

unrelated domain changes won’t break

your tests

Tuesday, July 14, 2009

build-test-data usage

Tuesday, July 14, 2009

class Author { String name static hasMany = [books: Book]}

class Book { String title static belongsTo = [author: Author]}

our domain

Tuesday, July 14, 2009

def book = Book.build()

assertNotNull book.authorassertNotNull book.title

just give me a book

Tuesday, July 14, 2009

def book = Book.build(title:“Infinite Jest”)

give me a book, but let me set the

title

Tuesday, July 14, 2009

def book = Book.build(author: Author.build(name: “Charlie Stross”))

let me tweak the book’s author

Tuesday, July 14, 2009

build-test-data features

Tuesday, July 14, 2009

‣ Domain objects (1..1, 1..N, N..N)

‣ Embedded domain objects

‣ String

‣ Boolean

‣ Number (Integer, Long, Float, etc)

‣ Byte

‣ Date

‣ Enum

‣ JodaTime

‣ Any other hibernate persistable class with a zero-argument constructor

build-test-data supports all

known attribute types

Tuesday, July 14, 2009

automatic constraint support

‣ nullable

‣ blank

‣ inList

‣ max

‣ maxSize

‣ min

‣ minSize

‣ range

‣ scale

‣ size

‣ url

‣ creditCard

‣ email

Tuesday, July 14, 2009

manual constraint support

‣ matches (regular expressions)

‣ validator (user-defined constraint)

‣ unique

Tuesday, July 14, 2009

// grails-app/conf/TestDataConfig.groovy

testDataConfig { sampleData = { Publisher { name = “Pragmatic Bookshelf” // default unless overridden } }}

configuration file lets you customize static attribute values

Tuesday, July 14, 2009

// grails-app/conf/TestDataConfig.groovy

testDataConfig { sampleData = { ‘com.example.Hotel’ { def i = 1 name = {-> “name${i++}” } // “name1”, “name2”, ... “nameN” } }}

configuration file lets you customize dynamic attribute values

Tuesday, July 14, 2009

grails install-plugin build-test-data

build-test-data installation

Tuesday, July 14, 2009

live coding demo

Tuesday, July 14, 2009

linksbuild-test-data home

http://bitbucket.org/tednaleid/grails-test-data/wiki/Home

intro blog posthttp://naleid.com/blog/2009/04/14/grails-build-test-data-01-plugin-released/

photo creditshttp://www.flickr.com/photos/kaptainkobold/3406169798/in/set-1058884

http://commons.wikimedia.org/wiki/File:Domain_model.png

http://www.flickr.com/photos/nickwheeleroz/2474196275/in/photostream

Tuesday, July 14, 2009

Questions?

Tuesday, July 14, 2009


Recommended