Discussion:
[Cucumber] organizing shared step definitions
r***@gmail.com
2018-02-07 12:43:32 UTC
Permalink
I have used cucumber to write tests for three similar sites. The tests live
in seperate directories, each of which contain a feature directory.
Now the test work, it is time to refactor.
When I compare the step definition files in the feature/step_definition
directories, I can see a lot of steps that are repeated in the three step
definition files.
I have moved them to a file 'shared_steps.rb' in those directories, but now
I have three identical shared_step.rb files.

Then I have moved the shared_steps.rb files to a newly created feature/lib
directory. The shared steps are automatically used by cucumber. But I can
not symlink that lib-directory from the first site to the other two sites:
cucumber does not include those. I tried another approach: making lib a
normal directory containing symlinks to the shared file. This works, but
this approach forces my to symlink each file I want to reuse.

What is the best approach to reuse code within the steps_definition and
support directory?

thanks in advance, Ruud
--
Posting rules: http://cukes.info/posting-rules.html
---
You received this message because you are subscribed to the Google Groups "Cukes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cukes+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Andrew Premdas
2018-02-08 13:42:35 UTC
Permalink
The best approach is probably to not write scenarios that are shareable.
Scenarios should be specific to your application. So the language you
should be using should be high level business language focusing on the
particular context of the application, and should be all about WHAT the
application does, not HOW it does things.

With this approach you will rarely have scenarios or steps that are easily
shared unless all your applications are very similar.

Lower down the stack, in your step definition or better yet helper methods
called by step definitions is the place to have shared code. Because this
is now code, not Gherkin, its easy to share, just like any other code.

There used to be alot of focus on sharing step definitions and scenarios,
but by 2011 this was being recognized as an anti-pattern by many of us.
Aslak summed that up nicely in this blog post
http://aslakhellesoy.com/post/11055981222/the-training-wheels-came-off as
shared steps were removed from Cucumber.

There is one library that is widely shared when Cuking, which is Capybara.
This is shared by creating a Gem and requiring it. Thats the pattern to
follow, but note it shares helper functions (Good), there is no sharing of
step definitions or scenarios.

All best

Andrew
Post by r***@gmail.com
I have used cucumber to write tests for three similar sites. The tests
live in seperate directories, each of which contain a feature directory.
Now the test work, it is time to refactor.
When I compare the step definition files in the feature/step_definition
directories, I can see a lot of steps that are repeated in the three step
definition files.
I have moved them to a file 'shared_steps.rb' in those directories, but
now I have three identical shared_step.rb files.
Then I have moved the shared_steps.rb files to a newly created feature/lib
directory. The shared steps are automatically used by cucumber. But I can
cucumber does not include those. I tried another approach: making lib a
normal directory containing symlinks to the shared file. This works, but
this approach forces my to symlink each file I want to reuse.
What is the best approach to reuse code within the steps_definition and
support directory?
thanks in advance, Ruud
--
Posting rules: http://cukes.info/posting-rules.html
---
You received this message because you are subscribed to the Google Groups "Cukes" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
------------------------
Andrew Premdas
blog.andrew.premdas.org
--
Posting rules: http://cukes.info/posting-rules.html
---
You received this message because you are subscribed to the Google Groups "Cukes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cukes+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
r***@gmail.com
2018-02-13 12:10:44 UTC
Permalink
Post by Andrew Premdas
The best approach is probably to not write scenarios that are shareable.
Scenarios should be specific to your application. So the language you
should be using should be high level business language focusing on the
particular context of the application, and should be all about WHAT the
application does, not HOW it does things.
With this approach you will rarely have scenarios or steps that are easily
shared unless all your applications are very similar.
Hi Andrew,
I understand your point. However in my case, the situation is different. We
are making sites that are created with building blocks in drupal. The sites
share code and share the way the look like. For example they all have the
same 'log in' button with the same underlying HTML, the menu's have
different items, but the HTML has the same structure.
That is why the test steps are alike: logging in is the same in all sites,
including the underlying HOW it is done, as well as selecting menu items .

I find it difficult to deal with this. Right now I have now three
directory's for three sites. The shared steps are included in the directory
tree using symlinks.
I have considered putting all code together in one directory with different
feature sub directories and sharing the same env.rb. In env.rb I could
select the site to test. But this leaves me with the problem that I have to
select the proper site specific steps: all shared steps are loaded by
default and then the steps that only apply to the selected site should be
loaded.


I don't know yet what the best strategy is to tackle this. All I know is
that there are now three similar sites and that there are many more to
come. I fear that using your advice (sharing the helper routines and NOT
the test steps) will result in a lot of code duplication (the step
definition). On the other hand gives it more flexibility to have
differences in behaviior of the steps. I cannot oversee which of these
considartions will prove to be more important in the future.

I appreciate your helping to find me the best way to put up a framework for
this.

Ruud
--
Posting rules: http://cukes.info/posting-rules.html
---
You received this message because you are subscribed to the Google Groups "Cukes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cukes+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
George Dinwiddie
2018-02-13 13:51:24 UTC
Permalink
Ruud,
Post by Andrew Premdas
The best approach is probably to not write scenarios that are
shareable. Scenarios should be specific to your application. So the
language you should be using should be high level business language
focusing on the particular context of the application, and should be
all about WHAT the application does, not HOW it does things.
With this approach you will rarely have scenarios or steps that are
easily shared unless all your applications are very similar.
Hi Andrew,
I understand your point. However in my case, the situation is different.
We are making sites that are created with building blocks in drupal. The
sites share code and share the way the look like. For example they all
have the same 'log in' button with the same underlying HTML, the menu's
have different items, but the HTML has the same structure.
That is why the test steps are alike: logging in is the same in all
sites, including the underlying HOW it is done, as well as selecting
menu items .
How are you including the shared building blocks? I don't know drupal,
but sharing functionality across projects is what libraries were meant
to solve. I don't suggest sharing the step definitions themselves, but
the code that the step definitions call to access the system under test.
Post by Andrew Premdas
I find it difficult to deal with this. Right now I have now three
directory's for three sites. The shared steps are included in the
directory tree using symlinks.
I have considered putting all code together in one directory with
different feature sub directories and sharing the same env.rb. In env.rb
I could select the site to test. But this leaves me with the problem
that I have to select the proper site specific steps: all shared steps
are loaded by default and then the steps that only apply to the selected
site should be loaded.
I don't know yet what the best strategy is to tackle this. All I know is
that there are now three similar sites and that there are many more to
come. I fear that using your advice (sharing the helper routines and NOT
the test steps) will result in a lot of code duplication (the step
definition). On the other hand gives it more flexibility to have
differences in behaviior of the steps. I cannot oversee which of these
considartions will prove to be more important in the future.
The step definitions that are the same for the multiple sites should be
one-liners, delegating to helper routines. Separate the expression of
business intent and the implementation details. The step definitions
should be oriented around business intent. The helper routines should
handle all of the implementation details.

- George
--
----------------------------------------------------------------------
* George Dinwiddie * http://blog.gdinwiddie.com
Software Development http://www.idiacomputing.com
Consultant and Coach http://www.agilemaryland.org
----------------------------------------------------------------------
--
Posting rules: http://cukes.info/posting-rules.html
---
You received this message because you are subscribed to the Google Groups "Cukes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cukes+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
r***@gmail.com
2018-02-13 14:38:46 UTC
Permalink
Post by George Dinwiddie
How are you including the shared building blocks? I don't know drupal,
but sharing functionality across projects is what libraries were meant
to solve. I don't suggest sharing the step definitions themselves, but
the code that the step definitions call to access the system under test.
The building blocks are part of the system in which the sites are created.
The test software is not related to the building blocks, apart from the
effect that the building blocks make the sites very similar.
Post by George Dinwiddie
The step definitions that are the same for the multiple sites should be
one-liners, delegating to helper routines. Separate the expression of
business intent and the implementation details. The step definitions
should be oriented around business intent. The helper routines should
handle all of the implementation details.
OK, I conclude from this it is better to have the tests for each site in a
seperate directory, each with its own features, env.rb and step definitions.
It is better to define the same step definitions for all sites as long as
the code that is used in the step definition is shared.

So I should not include for each site a file with this code:
When /I log in as (\S+) with password (\S+)\s*$/ do |user, pwd|
step "I fill in \"username\" with #{user}"
step "I fill in \"password\" with #{pwd}"
step "I press \"#{inlogbutton}\""
end

...but rather have a stepdefinition file in each site directory having code
like this:
When /I log in as (\S+) with password (\S+)\s*$/ do |user, pwd|
perform_login( user, pwd)
end

...along with a definition of perform_login that is shared with a library.

Still I find it difficult to accept that the step definition (which can
include heavier regular expressions and have more parameters) has to be
repeated each time. This has gived me problems already. I fear the number
of sites can grow to maybe 20-30. So that is a lot of duplication.
But I'll give it a try.

Ruud
--
Posting rules: http://cukes.info/posting-rules.html
---
You received this message because you are subscribed to the Google Groups "Cukes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cukes+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Andrew Premdas
2018-02-13 17:09:46 UTC
Permalink
Post by r***@gmail.com
Post by George Dinwiddie
How are you including the shared building blocks? I don't know drupal,
but sharing functionality across projects is what libraries were meant
to solve. I don't suggest sharing the step definitions themselves, but
the code that the step definitions call to access the system under test.
The building blocks are part of the system in which the sites are
created. The test software is not related to the building blocks, apart
from the effect that the building blocks make the sites very similar.
Post by George Dinwiddie
The step definitions that are the same for the multiple sites should be
one-liners, delegating to helper routines. Separate the expression of
business intent and the implementation details. The step definitions
should be oriented around business intent. The helper routines should
handle all of the implementation details.
OK, I conclude from this it is better to have the tests for each site in a
seperate directory, each with its own features, env.rb and step definitions.
It is better to define the same step definitions for all sites as long as
the code that is used in the step definition is shared.
When /I log in as (\S+) with password (\S+)\s*$/ do |user, pwd|
step "I fill in \"username\" with #{user}"
step "I fill in \"password\" with #{pwd}"
step "I press \"#{inlogbutton}\""
end
...but rather have a stepdefinition file in each site directory having
When /I log in as (\S+) with password (\S+)\s*$/ do |user, pwd|
perform_login( user, pwd)
end
...along with a definition of perform_login that is shared with a library.
Still I find it difficult to accept that the step definition (which can
include heavier regular expressions and have more parameters) has to be
repeated each time. This has gived me problems already. I fear the number
of sites can grow to maybe 20-30. So that is a lot of duplication.
But I'll give it a try.
Yes that conclusion is correct. Now you may have some step definitions that
you want to share because of your use of shared drupal modules. but alot of
experience suggests that

1) Not all the sites will be exactly the same
2) The main value of the tests will be found in exploring the differences.

So yes it might be a pain to repeat the step definition

Given "I am logged in as an admin"

on multiple sites. But if you implement that step with a helper method and
then share the method between your projects you will

1. Write better step definitions
2. Be able to manage the sharing better (sharing code is much more powerful
than sharing step definitions)
3. Have less problems in the long run

The last point is especially important when say Drupal change an existing
module that changes how you login, and half your applications have the old
module and the other half have the new module, and you now have a
functionality which used to be the same but now differs (and yes I know
that's unlikely with login, but surely you get my point).

One more point. If you have 20 or 30 sites that are all using the same
module why do you have to test that module 20 or 30 times? It seems like
you should move those tests upto the module level. I see this quite alot
when I am working with legacy code. Lots of tests are actually testing the
framework rather then how you are using the framework. This is silly we
know that frameworks like Drupal work (mostly) what we should be testing is
how we are using them specifically to solve the particular problems of each
site. Writing tests to say that an admin module has this link or that link
20 times is really silly. Running those tests for all those applications
thousands of time is even sillier (and very expensive). Perhaps you can
solve your problem by testing less at a higher level of abstraction and
moving all the remaining tests that are repetitive into the modules.

Remember all this is just friendly advice based on alot of experience. And
all my experience is just a drip in the ocean. Hopefully its of some use :)

All best

Andrew




Ruud
Post by r***@gmail.com
--
Posting rules: http://cukes.info/posting-rules.html
---
You received this message because you are subscribed to the Google Groups "Cukes" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
capybara (2) <https://mail.google.com/mail/u/0/#label/code/capybara>
------------------------
Andrew Premdas
blog.andrew.premdas.org
--
Posting rules: http://cukes.info/posting-rules.html
---
You received this message because you are subscribed to the Google Groups "Cukes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cukes+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
r***@gmail.com
2018-02-14 08:10:36 UTC
Permalink
Hi Andrew,
thank you for your extensive reply. I appreciate it very much. I realise I
am now in the position to make a wrong or good decision that can have a
large effect in the long term. I am glad I can fall back on the experience
of you guys.
Yes that conclusion is correct. But if you implement that step with a
helper method and then share the method between your projects you will
1. Write better step definitions
2. Be able to manage the sharing better (sharing code is much more
powerful than sharing step definitions)
3. Have less problems in the long run
The last point is especially important when say Drupal change an existing
module that changes how you login, and half your applications have the old
module and the other half have the new module, and you now have a
functionality which used to be the same but now differs (and yes I know
that's unlikely with login, but surely you get my point).
Yes, you are right. I have experienced this already on a small scale. But
you are right that this effect can give rise to big problems when the
number of applications increase.
One more point. If you have 20 or 30 sites that are all using the same
module why do you have to test that module 20 or 30 times? It seems like
you should move those tests upto the module level. I see this quite alot
when I am working with legacy code. Lots of tests are actually testing the
framework rather then how you are using the framework. This is silly we
know that frameworks like Drupal work (mostly) what we should be testing is
how we are using them specifically to solve the particular problems of each
site. Writing tests to say that an admin module has this link or that link
20 times is really silly. Running those tests for all those applications
thousands of time is even sillier (and very expensive). Perhaps you can
solve your problem by testing less at a higher level of abstraction and
moving all the remaining tests that are repetitive into the modules.
Yes, they will not be deployed at the same time. So there will be version
differences.
The tests will not be written by the drupal people to test their software,
but by the people who are responsible for the acceptance of it it. I guess
they will have another way of looking at it; they are mostly interested in
regression testing. Time will learn how this will work out.
Remember all this is just friendly advice based on alot of experience. And
all my experience is just a drip in the ocean. Hopefully its of some use :)
And it is much appreciated. Remember, the ocean is made up of drips.
Without drips, no ocean. Hopefully some day I can add a drip of experience
too ;)

Ruud
--
Posting rules: http://cukes.info/posting-rules.html
---
You received this message because you are subscribed to the Google Groups "Cukes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cukes+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...