Calling steps from steps definitions in Groovy (cuke4duke)

589 views
Skip to first unread message

Alejandro Cuesta

unread,
Apr 11, 2011, 12:55:34 PM4/11/11
to Cukes
Hi,

I need to reuse a step in Groovy:

Given (~/I look for "(.*)" in "(.*)"/) { what, where ->
// groovy code
}

to be called from another step:

When (~/I perform more than (.*) searches per minute/) { int number ->
(1..number).each {
Given('I look for "John Smith " in "London"')
}
}

But this doesn't work.

What's the best practice to do something like this in Groovy?

Cheers,

Alejandro

Andrew Premdas

unread,
Apr 12, 2011, 11:22:49 AM4/12/11
to cu...@googlegroups.com
Total guess as I know nothing about Groovy however

On 11 April 2011 17:55, Alejandro Cuesta <alejandr...@gmail.com> wrote:
Hi,

I need to reuse a step in Groovy:

Given (~/I look for "(.*)" in "(.*)"/) { what, where ->
     // groovy code
}

extract groovy code into a method e.g. foo(what, where)

to be called from another step:

When (~/I perform more than (.*) searches per minute/) { int number ->
       (1..number).each {
               Given('I look for "John Smith " in "London"')
       }
}

call method foo("John Smith", "London")
 

But this doesn't work.

What's the best practice to do something like this in Groovy?

Cheers,

Alejandro


Basically you never need to use nested steps, you can always use extract method and then call the method and it will always be simpler.

HTH

Andrew 
--
You received this message because you are subscribed to the Google Groups "Cukes" group.
To post to this group, send email to cu...@googlegroups.com.
To unsubscribe from this group, send email to cukes+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/cukes?hl=en.




--
------------------------
Andrew Premdas

CB Anderson

unread,
Apr 12, 2011, 12:06:24 PM4/12/11
to Cukes
I do this all the time in my groovy scripts - To expand a little on
what Andrew says, your solution might look something like this:

Given (~/I look for "(.*)" in "(.*)"/) { what, where ->
lookForUser(what, where)
}

When (~/I perform more than (.*) searches per minute/) { int number -
>
(1..number).each {
lookForUser(/*hardcoded values*/)
}
}

def lookForUser(what, where) {
//groovy code here
}

If you want to share the method throughout several step-def files, you
will need to do so through the World() - but I know you know this
already Alex ;)


On Apr 12, 4:22 pm, Andrew Premdas <aprem...@gmail.com> wrote:
> Total guess as I know nothing about Groovy however
>

Richard Paul

unread,
Apr 12, 2011, 2:14:07 PM4/12/11
to Cukes
To round out the discussion with code extracted into the 'World' you
can extract lookForUser out into a class:

Searcher.groovy
------
class Searcher {
def lookForUser(what, where) {
// do your searching
}
}

env.groovy
------
...
World {
new Searcher()
}

SearchSteps.groovy
------
Given (~/I look for "(.*)" in "(.*)"/) { what, where ->
lookForUser(what, where)
}

As the world object is set as the delegate of the above closure, any
methods that don't exist in scope are delegated to the world object.

You no doubt have many classes you would like to expose in the World
scope, you can simply mix them all into a base object.
World {
def world = new Object()
world.metaClass.mixin Searcher, SigninHelper // etc
world
}

HTH,
Richard

Alejandro Cuesta

unread,
Apr 12, 2011, 5:47:29 PM4/12/11
to Cukes
Andrew, Anderson... I've already tried your suggestions. Those were my
first attempts. The problem is that both steps are in different
definition files. One file can't see the method declared on the other
one

Another solution I tried is define a closure in a property, like this:

lookFor = { what, where -> // notice I'm setting a property,
not defining a method
go('/') // get.Browser is mixed in World
...
}

This works but it can't see the mixed methods, it can't see go('/').

Richard, you always nail the answer: I forgot trying:

world.metaClass.mixin Searcher, Browser

That could work but I'm not sure if Searcher could see geb.Browser
methods mixed in the World.
I'll try tomorrow morning in the office. I'll let you all know.

Thanks everyone for your replies.

Alex

Alejandro Cuesta

unread,
Apr 15, 2011, 7:03:04 AM4/15/11
to Cukes
I've found the solution!

I followed Richard suggestion and it worked except for one thing: I
didn't have an instance of Browser driven to my localhost site. So
instead of creating an Object instance, I created a Browser instance
and mixed the Searcher methods into Browser, like this:

import geb.Browser
import org.openqa.selenium.firefox.FirefoxDriver

this.metaClass.mixin(cuke4duke.GroovyDsl)

class Searcher {
def lookFor(what, where) {
go('/')
$('form')[0].looking_for = what
$('form')[0].location = where
$('input', value: "Search")[0].click()
}
}

World() {
def world = new Browser("http://localhost:8080/myApp")
world.metaClass.mixin Searcher
return world // added return for clarifcation
}

Anyway, I think my problem is about grouping concepts in the same step
definition files.
The concept of looking for someone once or searching 11 times is
essentially the same concept but written in a different way.

I am inclined to put both steps in the same file "search_steps".
This makes me think that it might be a good idea to write step
definition files corresponding to feature files. It's better to wrap
them in concepts. This can fix the problem of having "common step"
files.

Let me know your thoughts.

Cheers,

Alex


On Apr 12, 10:47 pm, Alejandro Cuesta <alejandro.cue...@gmail.com>
wrote:
Reply all
Reply to author
Forward
0 new messages