Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't @Given repeatable?

I am all new to Cucumber(jvm) and it all seems fine and dandy but :

I don't really know how to have multiple initial conditions (from various scenarios) written in various ways (elegantly) be implemented by a single method.

eg :

Scenario: I really am bad
    Given I really am inexperienced with Cucumber
    When I try to work
    Then what I produce is of poor quality

Scenario: I am on the way to become good (hopefully)
    Given I am a noob
    When I learn new things
    And I practice
    Then my level improves

Since Given I really am inexperienced with Cucumber and Given I am a cuke noob (although not semantically identical) are close enough for me to be implemented in the exact same way, I would like to be able to link them to the same method but

@Given("^I really am inexperienced with Cucumber$")
@Given("^I am a cuke noob$")
public void checkMyLevelIsGenerallyLow() throws Throwable {
    // some very clever code to assess then confirm my mediocre level ... something like if(true) ...
}

But the code presented here-above won't compile as the cucumber.api.java.en.@Given annotation is not java.lang.annotation.@Repeatable ...

one simple solution would be to do something like

public void checkMyLevelIsGenerallyLow() throws Throwable {
    // some very clever code to assess then confirm my mediocre level ... something like if(true) ...
}

@Given("^I really am inexperienced with Cucumber$")
public void check_I_really_am_inexperienced_with_Cucumber() throws Throwable {
    checkMyLevelIsGenerallyLow();
}

@Given("^I am a cuke noob$")
public void check_I_am_a_cuke_noob() throws Throwable {
    checkMyLevelIsGenerallyLow();
}

which would work just fine but would require lots of code for simple things and I am pretty sure there are other ways.

Or even, as I asked myself writing down this question, "Am I simply approaching this question from the right side ?", is what I am trying to acheive even a good idea in terms of BDD ?

I think it's not all bad since gherkin is supposed to hold the semantic and sentence construction and vocabulary choices are contexte (hence scenario) dependent. Yet I should be free of implementing it in whatever way I like.

So to wrap it all up :

  • Should @Given be @Repeatable ?
    • If so, why isn't it ? Is there another way around ?
    • If not, what am I missing in terms of approach ?
like image 250
Ar3s Avatar asked Apr 09 '15 13:04

Ar3s


3 Answers

Regarding multi-expressive @given

It might not be the nicest way to do it but scratching my head I thought of that :

@Given("^I really am inexperienced with Cucumber$|^I am a cuke noob$")
public void checkMyLevelIsGenerallyLow() throws Throwable {
    // some very clever code to assess then confirm my mediocre level ... something like if(true) ...
}

And it works ! It is exactly what I was looking for and can even be made a bit more readable like this :

@Given("^I really am inexperienced with Cucumber$"+
      "|^I am a cuke noob$")

Regarding the non-repeatability @given

as blalasaadri stated @Given may be @Repeatable but only from Java8 and further since @Repeatable was introduced in Java8.

Special thanks

To Ceiling Gecko who made me remember that the simplest and most obvious solutions are usually the best and most elegant.

like image 166
Ar3s Avatar answered Nov 12 '22 20:11

Ar3s


A long shot but wouldn't:

@Given("^I really am inexperienced with Cucumber$")
@And("^I am a cuke noob$")
public void checkMyLevelIsGenerallyLow() throws Throwable {
    // some very clever code to assess then confirm my mediocre level ... something like if(true) ...
}

work as expected?

like image 33
Ceiling Gecko Avatar answered Nov 12 '22 19:11

Ceiling Gecko


One reason for the annotation not being repeatable would be, that repeatable annotations are new with Java 8. Using them for a library is therefore still problematic as you'll be limiting the user base considerably. (Remember, especially big corporations are slow at adapting new technology.)

As an alternative you could use the same Java function and a similar Given description; such as

Given My cucumber level is low because I'm a cuke noob

and

Given My cucumber level is low because I'm inexperienced

which could both be caught by

@Given("My cucumber level is low because I'm (.*)")
public void checkMyLevelIsGenerallyLow(String reason) throws Throwable {
    // ...
}

This would also pass the reason to the function as its first argument. But I'm not sure you should use the same function here as the cases are different.

like image 1
blalasaadri Avatar answered Nov 12 '22 20:11

blalasaadri