Do your Groovy tests feel slower than they should?
I have been bouncing between Grails projects, plain Groovy libs, and some Java work, and the same theme keeps popping up. Tests get heavy fast once you pull in a database, fixtures, and a stack of XML. Groovy 1.7 landed with sweet touches like @Canonical and tighter syntax, Grails 1.2 is getting solid, and the Spock framework is making noise on the mailing lists. The pieces are here to make tests snappy and readable. The trick is to keep test data lightweight, stick to builders, and let specs tell the story. If your CI box is grumpy or your laptop fans spin during unit tests, this one is for you.
The short version: build data with tiny builders, write specs that read like real talk, and sidestep the database unless you truly need it.
The test data tax you do not need to pay
Big fixtures look helpful at first. Then they turn into slow baggage. Loading a dozen tables for a simple service test adds seconds that pile up. Also, fixtures have that growing pain where a name or a column changes and half the suite breaks for reasons that have nothing to do with your test. We can skip that by writing small builders in Groovy that make the right objects in memory with sane defaults. It feels like cheating because Groovy gives you named args, with, and closures that make builders tiny and pleasant.
Think Test Data Builder pattern, but even smaller thanks to Groovy.
class User {
String username
String email
boolean active = true
}
class UserBuilder {
String username = "user_${System.currentTimeMillis()}"
String email = "user@example.com"
boolean active = true
UserBuilder named(String name) { this.username = name; this }
UserBuilder withEmail(String mail) { this.email = mail; this }
UserBuilder inactive() { this.active = false; this }
User build() {
new User(username: username, email: email, active: active)
}
}
// usage
def user = new UserBuilder().named("lola").withEmail("lola@demo.com").build()That builder is boring in the best way. Defaults cover most tests. You only change what matters. Need a different email or a disabled user for a branch in your service? Call the tiny method. No fixture files, no setup class that touches a real database, no cascade of side effects. You control the edges and keep the rest quiet.
And since Groovy loves brevity, your test reads clean with almost no ceremony.
import org.junit.Test
class UserServiceTest {
def repo = new InMemoryUserRepo()
def service = new UserService(repo)
@Test
void "activates inactive accounts on login"() {
def u = new UserBuilder().named("max").inactive().build()
repo.save(u)
service.login("max")
assert u.active
}
}
class InMemoryUserRepo {
private Map<String, User> byName = [:]
void save(User u) { byName[u.username] = u }
User findByUsername(String name) { byName[name] }
}Notice the repo is just a map. That swap alone keeps tests fast and under your control. You can add a second implementation that hits the real store for an integration test block, but your everyday run stays in memory and quick.
Specs that read like stories
JUnit is still my default for muscle memory, but Spock is the one that makes people smile. The given when then style keeps focus on the behavior and away from plumbing.
import spock.lang.Specification
class PriceCalculatorSpec extends Specification {
def calculator = new PriceCalculator()
def "applies discount for loyal users"() {
given: "a loyal user and a base price"
def user = new UserBuilder().named("ruth").build()
def base = 100
when: "we compute the price"
def price = calculator.priceFor(user, base, loyalty: true)
then: "a ten percent discount kicks in"
price == 90
}
}With Spock you also get mocks and stubs that are painless. Interaction blocks say exactly what should happen, nothing more. That means fewer brittle tests and better feedback when something breaks. And because it is Groovy, the syntax stays compact.
If you are not ready to switch, no rush. You can still steal the ideas and keep writing JUnit with Groovy’s friendly asserts and builders.
Builders as tiny DSLs for tests
Once you have one builder, it is tempting to add a second one and wire them together with closures. Groovy makes this neat with delegate and with. Your tests end up with a small script vibe that explains the intent while hiding the noise. The builder owns the defaults and the boring parts. The test flips only the few knobs that matter.
My rule is simple. If I write the same four lines in three tests, I extract a builder.
class Order {
User buyer
List<LineItem> items = []
BigDecimal total
}
class LineItem {
String sku
int qty
BigDecimal price
}
class OrderBuilder {
UserBuilder ub = new UserBuilder()
List<LineItem> items = []
OrderBuilder buyer(Closure c) { c.delegate = ub; c.resolveStrategy = Closure.DELEGATE_FIRST; c(); this }
OrderBuilder item(String sku, int qty, BigDecimal price) { items << new LineItem(sku: sku, qty: qty, price: price); this }
Order build() {
def order = new Order(buyer: ub.build(), items: items)
order.total = items.collect { it.price * it.qty }.sum() ?: 0
order
}
}
// usage in a test
def order = new OrderBuilder()
.buyer { named("sara").withEmail("sara@shop.com") }
.item("A123", 2, 10)
.item("B777", 1, 25)
.build()Now your test focuses on rules like shipping, taxes, or fraud checks. No fixture files, no thick setup. If there is a part of the order you never touch in a given test, the builder keeps the defaults and you move on. This keeps refactors chill because changes live in one place.
One tiny tip. When you need unique values, lean on System.currentTimeMillis() or an atomic counter inside the builder so your tests do not trip on unique keys.
Speed tricks that feel like cheating
A few small switches can shave minutes. Use Expando or a map coercion to create stubs without pulling a whole mocking library when you just need a single method. Prefer in memory stores where possible. Keep I O and network off the hot path. Run fast unit tests in your IDE every time you save, and push the heavier checks to your CI loop. Groovy makes it easy to write helper methods that log any slow test over a threshold so you see slowness early.
No tool fight here. Whether you build with Maven or you are trying out Gradle, the patterns above still help.
// simple stub with Expando
def mailer = new Expando(
send: { to, subject, body -> true }
)
// or map coercion to an interface in Java land
interface Clock { long now() }
Clock fixedClock = [ now: { 123456789L } ] as Clock
assert fixedClock.now() == 123456789LOn the build side, split suites. A quick suite runs on save. A slower suite runs on commit. Your CI box can still run everything with coverage and reports, but your day to day flow stays fast. If you are using Hudson or TeamCity, you can have a little job that runs only your fast specs on a timer and a bigger job for the whole thing. This keeps feedback tight without starving the deeper checks.
Green tests you trust are better than big reports you ignore.
For folks on Grails
Grails comes with solid test support, but it is easy to opt into slow paths by default. You can stay quick by using unit tests with mockFor and by avoiding GORM calls in unit tests. Save the real DB traffic for the integration bucket. Builders help here too, because you can create domain objects in memory and only call save when you truly need to see the behavior in the database. This keeps your grails test-app run friendly while still catching the real gotchas in the right suite.
Also, skip loading the Spring context when the test does not need it.
class BillingService {
MailService mailService
Clock clock
BigDecimal charge(User user, BigDecimal amount) {
// imagine gateway call here
mailService.notify(user.email, "Charged ${amount} at ${clock.now()}")
amount
}
}
class BillingServiceTests extends grails.test.GrailsUnitTestCase {
void testChargeSendsMail() {
def user = new UserBuilder().named("nora").withEmail("nora@pay.test").build()
def sent = []
def mailStub = [ notify: { to, msg -> sent << [to: to, msg: msg]; true } ] as MailService
def clockStub = [ now: { 42L } ] as Clock
def svc = new BillingService(mailService: mailStub, clock: clockStub)
def amount = svc.charge(user, 19.99G)
assert amount == 19.99G
assert sent.size() == 1
assert sent[0].to == "nora@pay.test"
assert sent[0].msg.contains("42")
}
}Controllers get thinner and easier to test when services do the work, so push logic down. Grails taglibs are fast to unit test too, since they run with simple maps and strings. If you need to test URL mappings, keep a quick test for a few routes with the mapping tester and leave the rest to integration.
Keep the fast lane clean and the heavy lane honest.
Where to start tonight
Pick one flaky or slow test and replace its fixture with a builder. Swap the real repo for a map in memory. If you are curious about Spock, port a single JUnit test to a spec and read it out loud. Notice how the given when then steps make the case clear without extra words. Put a tiny counter or timestamp in your builders to dodge unique key pain. Commit with a smile when your run time drops.
Small wins add up fast.
Search terms that match what we covered today: Groovy testing, Spock framework, Grails unit tests, test data builders, Groovy mocks, fast tests.
Fewer fixtures, more builders, faster feedback.