organizing shared step definitions

58 views
Skip to first unread message

r.gro...@gmail.com

unread,
Feb 7, 2018, 7:43:32 AM2/7/18
to Cukes
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

Andrew Premdas

unread,
Feb 8, 2018, 8:42:44 AM2/8/18
to cu...@googlegroups.com
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

--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



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

r.gro...@gmail.com

unread,
Feb 13, 2018, 7:10:44 AM2/13/18
to Cukes


On Thursday, February 8, 2018 at 2:42:44 PM UTC+1, apremdas wrote:
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

George Dinwiddie

unread,
Feb 13, 2018, 8:51:35 AM2/13/18
to cu...@googlegroups.com
Ruud,

On 2/13/18 7:10 AM, r.gro...@gmail.com wrote:
>
>
> On Thursday, February 8, 2018 at 2:42:44 PM UTC+1, apremdas wrote:
>
> 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.

>
> 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
----------------------------------------------------------------------

r.gro...@gmail.com

unread,
Feb 13, 2018, 9:38:47 AM2/13/18
to Cukes


On Tuesday, 13 February 2018 14:51:35 UTC+1, George Dinwiddie wrote:
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.

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

Andrew Premdas

unread,
Feb 13, 2018, 12:09:56 PM2/13/18
to cu...@googlegroups.com
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

--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



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

r.gro...@gmail.com

unread,
Feb 14, 2018, 3:10:36 AM2/14/18
to Cukes

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
 
Reply all
Reply to author
Forward
0 new messages