Date post: | 13-Jul-2015 |
Category: |
Technology |
Upload: | ted-naleid |
View: | 6,192 times |
Download: | 7 times |
["Alice", "Bob", "Carol", "Dave"].each { new Author(name: it).save()}
iterators
closures
syntactic sugar
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
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
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
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
‣ 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
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
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