Graeme's Mock Example Chpt 6 pg 122 (1st ed)

0 views
Skip to first unread message

Steph Thompson

unread,
May 13, 2008, 6:00:19 PM5/13/08
to Groovy Users of Minnesota
I get the following failure notice when running the MockFor test
"No call to 'getParams' expected at this point. Still one call(s) to
redirect expected."

I won't take up space copying the code here. Its on page 122 of the
first ed.
of Definitive Guide To Grails.

I also obtained the source code from the book site. This test method
was
changed to use two mock objects and instead of "redirect" the code
uses "render" along with some other changes. (i.e. closure currying)

The new version test generates the same Failure message except
substituting
the word "render" for 'redirect'.

Has anyone already worked through this? This is my first excursion
into mocks.

Steph T

Steph Thompson

unread,
May 14, 2008, 10:06:40 AM5/14/08
to Groovy Users of Minnesota
Odd as it may sound I think I found an answer via Google. I searched
on the Failure message and found a reference to an email exchange
between Graeme and a gentleman at Refactr, Jesse O'Neill-Oine.
Strange I could not find that when I searched the Grails site.
Anyway, it suggests a solution. I am still new at mocks so if anyone
has references to web-sites or books for tutorial information on mocks
your suggestions will be appreciated.

Markmail reference: http://markmail.org/message/yh7334kc5z2crmpx

Steph T

Scott Vlaminck

unread,
May 14, 2008, 10:32:27 AM5/14/08
to groo...@googlegroups.com
The Groovy in Action book discusses mocks, but I don't remember how
much detail it provides.

Here are a few links from the groovy site that discuss mocks as well:

http://groovy.codehaus.org/Testing+Guide
http://groovy.codehaus.org/Groovy+Mocks
http://groovy.codehaus.org/Using+MockFor+and+StubFor


Also, this being your first mocking experience, if you start feeling
lost or uneasy, don't worry, it can take some getting used to. For
some other background reading, I recommend Hamlet's discussion about
Mocks, Stubs, and Spies:

http://hamletdarcy.blogspot.com/2007/10/mocks-and-stubs-arent-spies.html

And/or Martin Fowler's discussion on Mocks and Stubs:

http://martinfowler.com/articles/mocksArentStubs.html


Hope that helps.

Scott

--
-------------------------------------------------
Scott Vlaminck // sc...@refactr.com
Refactr LLC // http://refactr.com
mobile // 612-386-9382
-------------------------------------------------

Steph Thompson

unread,
May 14, 2008, 5:06:49 PM5/14/08
to Groovy Users of Minnesota
Thanks Scott for the pointers

My results so far:

Fowler Discussion: very clear about test-for-state and test-for-
behavior with the latter being the mock.
Hamlet's: added some info to Fowlers, but went on to
discuss enhancements to the framework that are further down the road
for me.

I understand that under Grails, Controllers are already 'mocked' and
to create another mock is incorrect.
I found some code to try in email exchanges with Graeme and others.

I was successful in asserting the state of the flash message in one
path of a controller method (update).
I was successful in asserting the redirectedUrl.
However it is "/test/edit/domain_object_id" and I don't understand why
there is "/test" as part of the url.
I get the same url if I run the tests in the test environment or the
dev environment.

Finally, what commands do I use to get the action value of just
'edit'. Other places in the update() method do not have flash
messages
and I want to access the actual action value set at various points in
the method (show, edit)
How do I access that value?

myController.params.action results in a null value.

any suggestions?

Steph T




On May 14, 9:32 am, "Scott Vlaminck" <sc...@refactr.com> wrote:
> The Groovy in Action book discusses mocks, but I don't remember how
> much detail it provides.
>
> Here are a few links from the groovy site that discuss mocks as well:
>
> http://groovy.codehaus.org/Testing+Guidehttp://groovy.codehaus.org/Groovy+Mockshttp://groovy.codehaus.org/Using+MockFor+and+StubFor
> -------------------------------------------------- Hide quoted text -
>
> - Show quoted text -

Steph Thompson

unread,
May 14, 2008, 11:55:03 PM5/14/08
to Groovy Users of Minnesota
I succeeded in completing Controller tests not so much by mocks
(behavioral testing) as in finding a state value at certain points in
a controller method. I used the redirectedUrl() to find out to where
the controller is sending the request.

However, I am having trouble of obtaining a testable value when the
controller uses the "render" method.

Any one know how to get a value set by render out of a controller?

Thanks,
Steph T
> >http://groovy.codehaus.org/Testing+Guidehttp://groovy.codehaus.org/Gr...

Zan Thrash

unread,
May 15, 2008, 11:17:02 AM5/15/08
to groo...@googlegroups.com
Steph,

Here is what I do for testing render code in my controllers.

Lets say I have a controller named "Foo" with a "bar" closure that renders a "show" view and some model.

In my test class under the setUp():

def renderParams = [:]
Foo.metaClass.render = {Maps args -> renderParams = args}

This will "intercept" all of the calls on you controller to "render" and dump it into your renderParams map.

Then in your actual test you can call the closure on the controller and make assertions like so.

assertEquals "show", renderParams.view
assert "some value on the model", renderParams.model.[someObject]?.[someAttribute]

Hope this helps,

Mike Hugo

unread,
May 15, 2008, 11:26:40 AM5/15/08
to groo...@googlegroups.com
Also take a look at http://jira.codehaus.org/browse/GRAILS-2630 which has several attachments including a "ControllerTestCase" that does the kind of thing Zan explains below and simplifies your tests by creating a "withController" closure you can use.  

Mike

Steph Thompson

unread,
May 15, 2008, 4:16:38 PM5/15/08
to Groovy Users of Minnesota
Mike & Zan

Thanks for the tips. I got the renderParams to work.
However, an equivalent redirectParams does not work.

I used the code examples and the Glen Smith tutorial referenced
in the GRAILS-2630 thread. But the "redirectParams.action" does not
resolve to a string, it resolves to an Object. i.e. I get the
closure# and HEX address
for the Object on a println statement. It gets worse when I place
that in an assertEquals().

Glen Smith uses the redirectParams.action in exactly the way you
suggested the
renderParams. I get the latter to work, but not the redirect
version.

setUp() {
def redirectParams = [:]
ServicerController.metaClass.redirect = { Map args -> redirectParams =
args }
mySC = new ServicerController(()

}

testUpdate() {

mySC.params.id = 15 //try retrieve a nonexistent record from DB
mySC.update.call()
assertEquals('edit", redirectParams.action)
}


This pattern works with "render" but not with "redirect". I am
watchful that
the conditionasl branch in update() under test is the correct either
"render" or
"redirect" as the testCase may be.

One other oddity: before declaring the "metaClass.render" I could
get the value of
mySC.response.redirectedUrl, but after the metaClass declaration the
redirectedUrl
returns null.


Thanks for your continued help.

Steph T



On May 15, 10:26 am, Mike Hugo <m...@piragua.com> wrote:
> Also take a look athttp://jira.codehaus.org/browse/GRAILS-2630which  
> has several attachments including a "ControllerTestCase" that does the  
> kind of thing Zan explains below and simplifies your tests by creating  
> a "withController" closure you can use.
>
> Mike
>
> On May 15, 2008, at 10:17 AM, Zan Thrash wrote:
>
>
>
> > Steph,
>
> > Here is what I do for testing render code in my controllers.
>
> > Lets say I have a controller named "Foo" with a "bar" closure that  
> > renders a "show" view and some model.
>
> > In my test class under the setUp():
>
> > def renderParams = [:]
> > Foo.metaClass.render = {Maps args -> renderParams = args}
>
> > This will "intercept" all of the calls on you controller to "render"  
> > and dump it into your renderParams map.
>
> > Then in your actual test you can call the closure on the controller  
> > and make assertions like so.
>
> > assertEquals "show", renderParams.view
> > assert "some value on the model", renderParams.model.[someObject]?.
> > [someAttribute]
>
> > Hope this helps,
>
> > Zan Thrash
>
> > On Wed, May 14, 2008 at 10:55 PM, Steph Thompson <SPTh...@frontiernet.net
> > > > - Show quoted text -- Hide quoted text -

Zan Thrash

unread,
May 15, 2008, 4:43:57 PM5/15/08
to groo...@googlegroups.com
Hey Steph,

I'm only guessing here (not having your controller code in front of me), but you are probably passing doing someting like this:

redirect (action: show, model:[model stuff] }

in your controller. This is perfectly legal and should work at run time but for testing you want to do this:

redirect (action:"show", model:[model stuff]}

The key is the quotation marks around your action.

In the first example you will be passing the 'show' closure back your test class.

In the second example you will pass the String "show" back to your test class. (much easier to make assertions against a String than a closure )


Hope this helps,

Zan Thrash

Steph Thompson

unread,
May 16, 2008, 7:49:57 AM5/16/08
to Groovy Users of Minnesota
Zan:

Third time's the charm!

quoting the action word in the redirect directive allows my tests to
find and process them.

However, the grails system doesn't quote them on generation (as it
does the render directive) .
So am I trying to test redirects incorrectly or at lease put to much
effort into it? It seems so to generate code, then have
to go back through it to place quotes around certain words.

Thanks for helping me get through this.

Steph T



On May 15, 3:43 pm, "Zan Thrash" <zanthr...@gmail.com> wrote:
> Hey Steph,
>
> I'm only guessing here (not having your controller code in front of me), but
> you are probably passing doing someting like this:
>
> redirect (action: show, model:[model stuff] }
>
> in your controller. This is perfectly legal and should work at run time but
> for testing you want to do this:
>
> redirect (action:"show", model:[model stuff]}
>
> The key is the quotation marks around your action.
>
> In the first example you will be passing the 'show' closure back your test
> class.
>
> In the second example you will pass the String "show" back to your test
> class. (much easier to make assertions against a String than a closure )
>
> Hope this helps,
>
> Zan Thrash <http://www.zanthrash.com>
>
> On Thu, May 15, 2008 at 3:16 PM, Steph Thompson <SPTh...@frontiernet.net>

Scott Vlaminck

unread,
May 16, 2008, 8:44:17 AM5/16/08
to groo...@googlegroups.com
If you don't quote the redirect param, you should be able to reference
the instance's closure for the assert:

assertEquals('edit', redirectParams.action)

becomes

assertEquals(mySC.edit, redirectParams.action)


Scott

Steph Thompson

unread,
May 16, 2008, 11:12:53 AM5/16/08
to Groovy Users of Minnesota
Scott:

Yep, that worked too. The assert compares two closures and
determines they are stored in the same memory location. This way
looks to be easier in that it does not require manually quoting terms
in the controller code.

The rule of thumb I am taking away from this is
(A) Render will return text
(B) Redirect will return closures

I just don't have the mind-set (yet) for groking testing of closures.
I want to default to a string of somesort.

Oddly, in some of my unsuccessful testing over the last couple of days
I did try "myController.edit" for a redirect
and received a closure_Memory_Location but at that point did not have
the metaClass reference of redirectParams to which to compare.

I also wonder what system Glen Smith is using because in his blog
MockFor(March): Unit Testing Grails Controllers he demos a test for
redirect of the Index() controller method. His test contains
assertTrue "form", redirectParams.action. I presume it works on his
machine. In my previous tests, Glen's code generated an error because
its a string compared to a closure.

At this point I paraphrase Lt. Savak's comment on humor from Wrath of
Khan: "Testing closures....a difficult concept."

Thanks All for your help

Steph T

To Do List:
---------------
1. Play in the Groovy Console with MetaClass concepts.

********************************************************************************
> ...
>
> read more »- Hide quoted text -
Reply all
Reply to author
Forward
0 new messages