Discussion:
[Cucumber] [CPP] Runtime steps generation, is it doable?
Max Kolesin
2018-08-14 20:39:03 UTC
Permalink
Hello everyone, I raised this question Cucumber-CPP gitter originally, but
so far have no responses and don't really know if people check it
regularly. So will duplicate here, apologies to everyone who might feel
being a victim of spam attack :)


How difficult would it be to allow runtime steps registration?

The desire is to be able to register steps like this:


#include <gtest/gtest.h>#include <cucumber-cpp/autodetect.hpp>
#include <unordered_map>#include <vector>
using cucumber::ScenarioScope;
struct SomeCtx
{
std::unordered_map<std::string, std::string> m_configuration;
};

GIVEN("^I create some context$")
{
ScenarioScope<SomeCtx> context;
}
std::unordered_map<std::string, std::string> all_possible_params(
{{"int param", "(\\d+)"},
{"double param", "(.*)"},
{"string param", "\"([^\"]*)\""}});
void somehow_called_registration_func(){
for (const auto &k : all_possible_params)
{
const auto &param_name = k.first;
const auto &param_reqexp = k.second;

WHEN("^I set " + param_name + " to " + param_regexp + "$", [&param_name](const auto &value))
{
ScenarioScope<SomeCtx> context;
context.m_conf[param_name] = std::to_string(value);
}
}
}


what would allow to then use generated steps in scenarios like this:


Given I create some contextWhen I set int param to 1And I set double param to 0.37And I set string param to "something"


What major problems with that approach do you foresee? I'm willing to
contribute, but don't really have a sense of how doable it is.
--
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-08-14 20:55:53 UTC
Permalink
There is a lot of history of people trying to create reusable step
definitions or step definition libraries. I think its not unfair to say
that all have failed. The reason is that scenarios should not have reusable
step definitions in them. Scenarios should contain steps that are

1. Specific to a particular business context
2. Have nothing in them about HOW to do something
3. Build on existing concepts that are specific to your particular business
concept

What these libraries encouraged was the creation of badly written
unsustainable scenarios. Your generated steps would repeat this mistake.

Writing step definitions is a trivial problem that you don't need any help
with. A good step definition only requires

1. A unique string to identify it
2. An implementation that is a single method call to implement it.

You don't need to do anything else. You don't need to automate, generate or
provide pre-existing solutions. The only thing you need to do is to find
that unique string.

All best

Andrew
Post by Max Kolesin
Hello everyone, I raised this question Cucumber-CPP gitter originally, but
so far have no responses and don't really know if people check it
regularly. So will duplicate here, apologies to everyone who might feel
being a victim of spam attack :)
How difficult would it be to allow runtime steps registration?
#include <gtest/gtest.h>#include <cucumber-cpp/autodetect.hpp>
#include <unordered_map>#include <vector>
using cucumber::ScenarioScope;
struct SomeCtx
{
std::unordered_map<std::string, std::string> m_configuration;
};
GIVEN("^I create some context$")
{
ScenarioScope<SomeCtx> context;
}
std::unordered_map<std::string, std::string> all_possible_params(
{{"int param", "(\\d+)"},
{"double param", "(.*)"},
{"string param", "\"([^\"]*)\""}});
void somehow_called_registration_func(){
for (const auto &k : all_possible_params)
{
const auto &param_name = k.first;
const auto &param_reqexp = k.second;
WHEN("^I set " + param_name + " to " + param_regexp + "$", [&param_name](const auto &value))
{
ScenarioScope<SomeCtx> context;
context.m_conf[param_name] = std::to_string(value);
}
}
}
Given I create some contextWhen I set int param to 1And I set double param to 0.37And I set string param to "something"
What major problems with that approach do you foresee? I'm willing to
contribute, but don't really have a sense of how doable it is.
--
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.
Max Kolesin
2018-08-14 21:13:55 UTC
Permalink
Andrew, thanks I get your point.

Although it is not really purpose of this topic, as I was more enquiring
about Cucumber-CPP implentation details, I'm curious for a short follow up.

Shouldn't set of steps that we have come from business (managers/product
owners/etc) that don't really have full understanding of how things work
under the hood?
If that's true, and assuming that for each step there should be a single
method to call it creates a direct mapping between your code interface and
steps, which to me doesn't seem like a good thing to have.
Is my thought process wrong here?

Regards,

Max
--
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-08-15 05:53:23 UTC
Permalink
I see Step definitions as a translation layer to get from something
business to something automated, and I don't use them for anything else.
The methods they call make a test-api which should be all about WHAT things
do, not about HOW they work. How things work starts getting exposed in the
body of these methods. So (in ruby)

Scenario: Sign in
Given I am registered
When I sign in
Then I should be signed in

# sign_in_steps.rb

module SignInStepHelper
def sign_in(user: )
# this is the start of HOW we sign in
...
end

def register(user: )
# this is the starting point for HOW we register
...
end
end

Given "I am registered" do
register(user: @i)
end

When "I sign in" do
sign_in(user: @i)
end

So now you have moved the entry points that expose HOW things are done
further down your stack away from your step definitions and gherkin and
into your programming language domain which is much better at dealing with
HOW things are done.

One of the benefits of this is that you can have several step definitions
that do roughly the same thing without any duplication (because they just
make the same call) e.g.

When 'Sally registers' do
register(user: @sally)
end

Given "I am signed in as an admin" do
sign_in(user: create_admin_user)
end

...

Now I have taken a couple of liberties here to keep this reply reasonably
short

1. I've used sign in as an example.
Sign in is a good example because nearly everyone can understand the
context without further explanation
Sign is a really bad example because unlike 99% of your scenarios it has a
context which really doesn't explain any part of your business.

2. I've put things together that I would probably separate e.g.
registration

I hope thats of some use, and that you can see that re-use and generation
is just not needed here, as you would be generating calls, not
implementations.

All best

Andrew
Post by Max Kolesin
Andrew, thanks I get your point.
Although it is not really purpose of this topic, as I was more enquiring
about Cucumber-CPP implentation details, I'm curious for a short follow up.
Shouldn't set of steps that we have come from business (managers/product
owners/etc) that don't really have full understanding of how things work
under the hood?
If that's true, and assuming that for each step there should be a single
method to call it creates a direct mapping between your code interface and
steps, which to me doesn't seem like a good thing to have.
Is my thought process wrong here?
Regards,
Max
--
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.
Loading...