27
2008
MockFor(March): Unit Testing Grails Services
Ok. We’ve had a look at Taglibs and Controllers, it’s time to take a looks at Services. Let’s start with a simple one… My NotificationService gets called when people post new comments. But before we send a notification, we check to see whether notifications are turned on for the blog in question. This requires a little navigation of the object graph…
boolean isEmailNotifyActive(Comment comment) {
BlogProperty bp = comment.blogEntry.blog.blogProperties?.find { prop ->
prop.name == "emailNotify"
}
return bp ? Boolean.valueOf(bp.value) : false
}
So the only mockery required is making sure that object graph navigation works. I *have* to pass in a real comment since the arg is strongly typed… and I have to return a BlogProperty from the final find… but other than that, you can mock till it’s 1999…
void testIsEmailActive() {
def bp = [name: 'emailNotify', value: 'true']
Comment.metaClass.getBlogEntry = { -> [ blog: [ blogProperties: [
bp
] ] ] }
def comment = new Comment()
assertTrue ns.isEmailNotifyActive(comment)
bp.value = 'false'
assertFalse ns.isEmailNotifyActive(comment)
}
So we can mock our way through all the object graph navigation using nested maps, but just make sure that we return a BlogProperty object at the end. We’ll go for the gold and check for both the positive and affirmative. Test coverage markers now work in IntelliJ Groovy Test cases (since 7.0.3), so let’s do a “Run with Coverage”…
Ok. Not quite 100%, but we’re underway… What’s the IDE source telling us…
Well those markers are pretty hard to see… but nothing’s red. Not sure why some things are off-pink
… that code certainly *seems* to be being covered.. Need to circle back later and check that out.
Let’s try something a little more meaty…sendMailNotification() invokes the actual MailService which is injected into NotificationService by Grails. It should be trickier to mock…
def sendEmailNotification(Comment comment, String address, String baseUri) {
log.debug "Sending new notification to ${address} on comment to ${comment.blogEntry.title}"
mailService.send(address,
"""
// lots of markup stuff here around the comment
""",
"[Gravl] New comment for ${comment.blogEntry.title} by ${comment.author}")
}
Just need to pass in a mock MailService to the NotificationService and we’re done right? Right. But MailService is defined in the NotificationService as:
MailService mailService
So we’re talking concrete class – no hashmap will mock this bad boy. Given this is MockFor(March)… it’s probably time to take advantage of the MockFor() support in Groovy:
void testSendEmailNotification() {
String.metaClass.encodeAsWiki = { -> delegate }
def bp = [name: 'emailNotify', value: 'true']
Comment.metaClass.getBlogEntry = { -> [ blog: [ blogProperties: [
bp
] ], toPermalink: {}, title: 'Sample Post' ] }
def comment = new Comment(body: "sample body", author: "Joe User")
def mockMail = new MockFor(MailService.class)
def result = [:]
mockMail.demand.send(1) { address, body, title ->
result.address = address
result.body = body
result.title = title
}
mockMail.use {
ns.mailService = new MailService()
ns.sendEmailNotification(comment,"abc@abc.com", "http://localhost/demo/")
}
assertEquals "abc@abc.com", result.address
assertEquals "[Gravl] New comment for Sample Post by Joe User", result.title
}
The interesting bit here is how we mock out the mail service using MockFor(). My mock mail service just captures the incoming params to the send() call (since it’s not the class under test here – I’m just check that my NotificationService is passing it the right stuff). And we’re in business.
Alrighty that’s enough mocking for one day.. Time to go and look at mocking some seemingly unmockable parts of Gravl. I’ll let you know how I go..
3 Comments + Add Comment
Leave a comment
Glen Smith
Archives
- January 2012
- November 2011
- October 2011
- September 2011
- August 2011
- July 2011
- June 2011
- April 2011
- March 2011
- January 2011
- November 2010
- October 2010
- September 2010
- August 2010
- July 2010
- June 2010
- May 2010
- April 2010
- February 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
- August 2006
- July 2006
- June 2006
- May 2006
- April 2006
- March 2006
- February 2006
- January 2006
- December 2005
- November 2005
- October 2005
- September 2005
- August 2005
- July 2005
- June 2005
- May 2005
- April 2005
- March 2005
- February 2005
- January 2005
- December 2004
- November 2004
- October 2004
- September 2004
- August 2004
- July 2004
- June 2004
- May 2004
- March 2004
- February 2004
- January 2004
- December 2003
- November 2003
- October 2003
- September 2003

An article by Glen





Hiya!
Thanks for the great postings on testing. It seems there are basically nothing like these available as of now (is there?).
I would like to test a Service where I fetch data via the domain class, e.g. Account.executeQuery(“select Book b where b.pages > :pageCount”, [pageCount:100]). Do you have any idea how this could be made to work? I tried fiddling around metaclasses a bit, but it reported no method matching arguments executeQuery(String, Map) was found. It also seemed IntelliJ dea (8.0M1) couldn’t resolve my service class so I had to run the tests on command line.
Thumbs up for your efforts and thanks in advance for any advice you might have!
Heh, it seems I made some fundamental errors (such as trying to access services in a Unit test compared to an Integration test). I now seem to have got it working, so please ignore the last comment
(It seems asking newbie questions always helps in getting things solved rapidly on ones own!)
Nice post.
Have written a series of post on unit testing grails controllers and mocking in general
http://gitshah.blogspot.com/2010/04/unit-testing-grails-controller-part-1.html
http://gitshah.blogspot.com/2010/04/how-to-use-mocks-to-verify-behaviour-in.html
It would be great if you could give some feedback