tednaleid / grails-test-data (http://grails.org/plugin/build-test-data)

Build Test Data plugin for grails. Decorates domain objects with "build" method that will inspect constraints and automatically create and save a valid domain object. Build method takes an optional map parameter that lets the caller set values. Authors: Ted Naleid and Joe Hoover

The plugin should be able to generate simple to moderately complex objects and satisfy all of their constraints right out of the box without any additional configuration.

Further refinements to the object graph persistence are being worked on, and it's definitely possible to get your domain objects configured such that the plugin (or any other code) will be unable to automatically create and save an object.

Simple Application Example

Create a new application called bookstore and install the build-test-data plugin:

grails create-app bookstore

cd bookstore

grails install-plugin build-test-data

Create an Author domain class:

grails create-domain-class Author

And give it the following contents:

class Author {
    String firstName
    String lastName
    
    static hasMany = [books: Book]
    
    static constraints = {
        firstName(blank: false)
        lastName(blank: false)
    }
    public String toString() {
        "$firstName $lastName"
    }
}

Then create a Book domain class:

grails create-domain-class Book

With these contents:

class Book {
    String title
    Date published
    BigDecimal price

    static belongsTo = [author: Author]
    
    static constraints = {
        title(blank: false)
        published(nullable: false)
        price(nullable: false, scale: 2, min: 5.95 as BigDecimal)
        author(nullable: false) 
    }

    public String toString() {
        "$title published on $published by $author costs \$$price"
    }
}

Now, load up the grails console and lets try build on our new domain objects:

grails console

And try this script:

def a = Author.build()
println "First Name: $a.firstName"
println "Last Name: $a.lastName"
println "Author ID: $a.id"

The plugin will automatically create a new Author object, populate the required firstName and lastName fields, and save the object (giving it an id). If you run the script, you should see output like this:

First Name: firstName
Last Name: lastName
Author ID: 1

By default, for String values, the plugin will just try to use the field name as the value (truncating or expanding as necessary if there are string length limitations).

If you want to specify the first name, just pass that in a map that you pass to build on the first line:

def a = Author.build(firstName: "Daniel")

That modified script prints:

First Name: Daniel
Last Name: lastName
Author ID: 2

With Book, we have a more complex domain class. It has a few different property types and it also has required related domain class of Author.

If you don't care about any of the specific values on the book, you can simply call build() to have a valid, saved book instance:

def b = Book.build()
println "Book title: $b.title"
println "Book price: $b.price"
println "Book published: $b.published"
println "Book author: $b.author"
println "Book id: $b.id"

Prints:

Book title: title
Book price: 5.95
Book published: Mon Apr 13 23:11:34 CDT 2009
Book author: firstName lastName
Book id: 1
Book author id: 3

Again, if you want to override some of the values, you can pass them in the map:

def b = Book.build(title: "Tomorrow Midnight", author: Author.build(firstName: "Ray", lastName: "Bradbury") )
println "Book title: $b.title"
println "Book price: $b.price"
println "Book published: $b.published"
println "Book author: $b.author"
println "Book id: $b.id"
println "Book author id: $b.author.id"

Resulting in:

Book title: Tomorrow Midnight
Book price: 5.95
Book published: Mon Apr 13 23:13:22 CDT 2009
Book author: Ray Bradbury
Book id: 2
Book author id: 4

The build-test-data plugin lets you concentrate on the data that's pertinent to your test, rather than building and maintaing large datasets that aren't tailor made for your test.

See the SampleCode page for additional examples.


This revision is from 2010-01-08 23:51