Top Banner
grails build-test-data plugin created by Ted Naleid and Joe Hoover Tuesday, July 14, 2009
45
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Grails build-test-data Plugin

grailsbuild-test-data

plugin

created by Ted Naleid and Joe Hoover

Tuesday, July 14, 2009

Page 2: Grails build-test-data Plugin

creating test data with groovy is easy!

Tuesday, July 14, 2009

Page 3: Grails build-test-data Plugin

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

iterators

closures

syntactic sugar

Tuesday, July 14, 2009

Page 4: Grails build-test-data Plugin

modeling your domain in grails is easy!

Tuesday, July 14, 2009

Page 5: Grails build-test-data Plugin

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

Page 6: Grails build-test-data Plugin

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

Page 7: Grails build-test-data Plugin

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

).save()

test data must pass constraints

Tuesday, July 14, 2009

Page 8: Grails build-test-data Plugin

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

Page 9: Grails build-test-data Plugin

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

Page 10: Grails build-test-data Plugin

problem multiplied by complex domain models

Tuesday, July 14, 2009

Page 11: Grails build-test-data Plugin

agile + code coverage = lots of tests

Tuesday, July 14, 2009

Page 12: Grails build-test-data Plugin

you need to add a new constraint...

what happens to all the tests?

Tuesday, July 14, 2009

Page 13: Grails build-test-data Plugin

Tuesday, July 14, 2009

Page 14: Grails build-test-data Plugin

creating maintainable test data is hard!

Tuesday, July 14, 2009

Page 15: Grails build-test-data Plugin

existing test datacreation strategies

Tuesday, July 14, 2009

Page 16: Grails build-test-data Plugin

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

Page 17: Grails build-test-data Plugin

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

Page 18: Grails build-test-data Plugin

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

Page 19: Grails build-test-data Plugin

// 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

Page 20: Grails build-test-data Plugin

all of these strategies strive to DRY up your test data

creation

Tuesday, July 14, 2009

Page 21: Grails build-test-data Plugin

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

Tuesday, July 14, 2009

Page 22: Grails build-test-data Plugin

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

Page 23: Grails build-test-data Plugin

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

Page 24: Grails build-test-data Plugin

you can with the build-test-data plugin

Tuesday, July 14, 2009

Page 25: Grails build-test-data Plugin

build-test-data advantages

Tuesday, July 14, 2009

Page 26: Grails build-test-data Plugin

testing data documents what’s being tested

Tuesday, July 14, 2009

Page 27: Grails build-test-data Plugin

only specify values the test uses

Tuesday, July 14, 2009

Page 28: Grails build-test-data Plugin

test coupling is eliminated

Tuesday, July 14, 2009

Page 29: Grails build-test-data Plugin

you’re executing real GORM code paths

Tuesday, July 14, 2009

Page 30: Grails build-test-data Plugin

unrelated domain changes won’t break

your tests

Tuesday, July 14, 2009

Page 31: Grails build-test-data Plugin

build-test-data usage

Tuesday, July 14, 2009

Page 32: Grails build-test-data Plugin

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

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

our domain

Tuesday, July 14, 2009

Page 33: Grails build-test-data Plugin

def book = Book.build()

assertNotNull book.authorassertNotNull book.title

just give me a book

Tuesday, July 14, 2009

Page 34: Grails build-test-data Plugin

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

give me a book, but let me set the

title

Tuesday, July 14, 2009

Page 35: Grails build-test-data Plugin

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

let me tweak the book’s author

Tuesday, July 14, 2009

Page 36: Grails build-test-data Plugin

build-test-data features

Tuesday, July 14, 2009

Page 37: Grails build-test-data Plugin

‣ 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

Page 38: Grails build-test-data Plugin

automatic constraint support

‣ nullable

‣ blank

‣ inList

‣ max

‣ maxSize

‣ min

‣ minSize

‣ range

‣ scale

‣ size

‣ url

‣ creditCard

‣ email

Tuesday, July 14, 2009

Page 39: Grails build-test-data Plugin

manual constraint support

‣ matches (regular expressions)

‣ validator (user-defined constraint)

‣ unique

Tuesday, July 14, 2009

Page 40: Grails build-test-data Plugin

// 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

Page 41: Grails build-test-data Plugin

// 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

Page 42: Grails build-test-data Plugin

grails install-plugin build-test-data

build-test-data installation

Tuesday, July 14, 2009

Page 43: Grails build-test-data Plugin

live coding demo

Tuesday, July 14, 2009

Page 44: Grails build-test-data Plugin

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

Page 45: Grails build-test-data Plugin

Questions?

Tuesday, July 14, 2009