6

I do know that basically all Given, When, Then and And keywords in feature definition technically are not distinguished by Cucumber. But why does Cucumber have different annotations for the step definitions @Given, @When, @Then and @And?.

What I am observing is either you have the code describing the step:

@When("^first operand = \"(.+?)\"$")
public void setFirstOperand(String firstOp){
    firstOperand = Integer.parseInt(firstOp);
}

or you have the code:

@Then("^first operand = \"(.+?)\"$")
public void setFirstOperand(String firstOp){
    firstOperand = Integer.parseInt(firstOp);
}

both execute the logic of the test in the identical way.

Is there any difference how Cucumber framework treats the code under those different annotations? I believe there should be some difference otherwise this architecture (when you have different entities intended to address the same logic) would not look pretty "object-oriented".

2

It seems that your question was misunderstood several times and not even your comments fixed this situation. I think at least I got your question right - at least I find it quite clear: It's not about the DSL, it's about the annotations for test steps.

Unfortunately I can't answer why cucumber actually has different annotations for step definitions, but I know why I would have designed the API with those different annotations, if I had designed it.

I'm not at all an expert for cucumber but I find the way the semantics of Given, as described in cucumber's Gherkin specification quite contradictory. It starts sensibly:

Given steps are used to describe the initial context of the system - the scene of the scenario. It is typically something that happened in the past.

Perfect! Clearly a precondition, right? Could mean if this precondition isn't fulfilled, the scenario simply doesn't apply.

The next sentence of the same description destroys this hope:

When Cucumber executes a Given step, it will configure the system to be in a well-defined state, such as creating and configuring objects or adding data to a test database.

That's definitely not what we call separation of concerns - I'd rather call it messing up concerns.

For configuring a system to be in a well-defined state we usually have setup tasks with @Before annotations or whatever.

In natural English (I'm not a native speaker so I might be slightly wrong) Given introduces a precondition. And that's exactly where we COULD benefit from a specific @Given annotation (cucumber seems to have missed this chance): it could (and I think should) annotate a boolean function that indicates whether or not the test (all the Whens and Thens as well as further Given conditions) are applied or not.

In simpler words: ideally tests would never fail if a precondition isn't fulfilled. This would introduce significantly enhanced flexibility regarding test data.

Back to natural language (well, somewhat semi-natural):
"Given you accepted the meeting. When the meeting starts, Then I expect you to be in the meeting room."

Here I'm saying that all the rest only applies if you accepted the meeting. If you didn't the meeting might not start and even if it starts I won't expect you to be in the meeting room.

And this is where the value of a specific @Given annotation could come in: a test runner could ignore all tests or all outline records that don't match the precondition. In a similar manner as JUnit deals with assumeThat.

I could imagine that the designers of the API had something like this in mind. Maybe after the API design was finished, there wasn't enough time to implement it like this, or the people implementing the solution had a different opinion.

Since the test runner obviously isn't implemented in the way the different annotations suggest, I suppose it is what you seem to be perceiving: a design flaw.

Even worse this flaw leaks into the DSL. Because it means that the keywords have no specific semantics either.

And obviously enhanced semantics for the existing DSL and API can't be introduced without potentially breaking existing tests - or even more probable and even worse: hiding errors that existing tests now cover by abusive Given semantics.

Sorry for having wasted so many words for again not answering your question. But at least now you have an answer that addresses your question - and you have found a fellow sufferer.

  • I don't see any value added by this answer except showing sympathetic view towards OP. – Vishal Aggarwal Apr 7 at 3:14
  • 1
    @Vhishal Aggarwal, I'm sorry that you can't see any value added by my answer. As a reparation I'll try my best to find value in your comment. – yaccob Apr 7 at 3:29
  • @VishalAggarwal OP was asking about the technical differences between the different annotations Cucumber provides, and your answer did not address this. yaccob provided some possible justifications for why there would be multiple annotations that seem to do the exact same thing, which seems to be the best post so far – Vivek Chavda 2 days ago
4

The problem Cucumber addresses, is communication not architecture.

These keywords are just syntactical sugar , for the business user's understanding and readability. Technically there is no difference.

Having said that, the whole concept of Cucumber (BDD) is to have a common shared vocabulary(DSL) so all team members can communicate on same level including non- technical people.

The value received is for the whole team in terms of improved communication by a shared vocabulary.

As far as coding is concerned,

A function's job is to return the current state of the application, it's test's job to determine (assert) it is positive or negative based on the given test scenario and pass or fail the test accordingly.

So a function can return a same state which might be determined positive/ or negative by the test script depending on scenario it's currently validating.

  • 1
    Thanks for your answer! But it seems that you are talking about the feature definition. If we talk about the "users" the approach might make sense, but we're talking about programming framework that is written by coders for coders. The better readability in that case rather means the better structure and adhering OOP programming best practices. As for a programmer it would be more readable if there would be, say, the annotation like "@StepDef(type = EStepType.GIVEN, regexp="..."). – Alexey R. Jul 18 '18 at 9:39
  • The whole concept of Cucumber (BDD) is to have a common shared vocabulary(DSL) so all team can communicate using it on same level including non- technical people. – Vishal Aggarwal Jul 18 '18 at 9:55
  • Yes, but what value do you as a developer get from either the step will be Given or When or Then if there will no be difference in implementation or in logic. This will only increase uncertainty of your code since you will code the step as if it would be Given but the user will be able to use it as if it would be Then – Alexey R. Jul 18 '18 at 9:57
  • 1
    Vocabulary without distinct semantics is not a DSL. And I doubt that sharing 3 words that are arbitrarily interchangeable improves communication. – yaccob Apr 7 at 3:59
  • 1
    I am really sorry if Cucumber specification does not meet your requirements.I understand your concern but Cucumber issue repo would be better place if something needs to be updated/fixed in cucumber. – Vishal Aggarwal Apr 7 at 13:17
1

The cucumber keywords like Given, When, And, But, Then are used to enhance the readability and understand ability of the scenario which the QA is planning to test in the scenario.

The idea of the BDD framework like cucumber is to enhance the knowledge of what is being tested to people outside the testing layer like the BAs and the developers or product owners.

The syntax of a typical scenarios is like as follows:

Scenario: Some determinable business situation

Given some precondition exists

And some other precondition exits

When some action by the actor

And some other action

And yet another action

Then some testable outcome is achieved

And something else have also happened
0

Typically you setup your scenario in the given step , this could be connecting to a service , loading it's configuration, priming its fixtures

In the when step you have the principal action you are testing , this could be a user request or a service taking an action.

You could chain actions with and steps .

Finally the then step will verify the action occurred, this can be by asserting about the resulting data or state .

With good step design you can reuse steps between features to increase coverage and efficiency.

This is best achieved with careful parameterisation of the steps to make them extensible.

You can also use tables in your features to run a step multiple times with different data from the table rows each time.

You can also run the same steps with values hardcoded in to the feature lines.

Other than looping if you use tables there is no difference in how those functions are invoked by cucumber than any other. At least in most implementations i've seen but it may be different in yours. You could run it in a debugger and check.

Some custom tools like SpecFlow pass around all sorts of other objects and state to allow you to construct the scenario you are testing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.