I really like the idea behind this extension.
But, when you are testing a stateless system, chiefly an API, then the resulting state of our steps is handled by no one. This is the case for this extension.
(Even though most of the time, if you are at Level 3 of the Richardson Maturity Model, you can use HATEOS & Hypermedia to follow _links but this is not always possible - hence the necessity of a solution which your extension solves really well.)
This discussion was very interesting to me and I think you guys are solving something important.
@jakzal said I shouldn't debug to see where these things come from. This should be self-explanatory imo. Explicit.
In regards to readability, I wonder if one might consider the following as on top of what was discussed, I think:
- It currently is not easy to read and understand the scenario
- Currently, the scenario is being shifted to in the Context classes when it should stay in the
.feature files
- storeKeys are only made available in the context
- It is not possible to store more than 1 instance in the store of the same type without having to keep track of the store keys used in the annotation provided
- reading the feature is not enough to know the state of the store (we should now the state of the store by reading the feature)
Behat scenarios are all about state. First you put the system under test to a special state through the Given steps. Then you continue to manipulate your system through When steps and finally testing the resulting state via the Then steps.
It should be the same for the store.
How about using the gherkin language instead?
Feature: Gorilla Lunch Basket
In order for a gorilla to eat at lunch time
He needs to be able to gather bananas from his fellow bonobos
And keep them in his basket
Scenario: A bonobo can take a banana and give it to a gorilla for him to eat
Given there is a bonobo "@bonobo"
And there is a tree with 1 banana "@banana"
And there is a gorilla "@gorilla"
When bonobo "@bonobo" takes banana "@banana"
And bonobo "@bonobo" gives banana "@banana" to gorilla "@gorilla"
Then gorilla "@gorilla" should have 1 banana left in his basket
When I send an api request to get gorilla "@gorilla" basket
Then the response status code should be 200
And the "count" property should equal 1
When gorilla "@gorilla" eats 1 banana
Then gorilla "@gorilla" should have 0 banana in his basket
When I send an api request to get gorilla "@gorilla" basket
Then the response status code should be 200
And the "count" property should equal 0
This would be more explicit, and would allow to identify the store keys easily. Now, we know all objects being stored start with @ (it could be any notation) but when reading the test, it is more readable and really takes on the power of your extension which is the ability to store stuff between contexts easily.
You can then imagine the following when things get tricky:
Scenario: Many bonobos can take many bananas and give them to a gorilla for him to eat
Given there are the following 2 bonobos
| storeKey | name |
| @bonobo1 | Monkey Chan |
| @bonobo2 | Bonono Chan |
And there is a tree "@tree" with the following 3 bananas
| storeKey | name |
| @banana1 | Yellow Banana |
| @banana2 | Yellowish Banana |
| @banana3 | Greenish Banana |
When I send an api request to get tree "@tree" details
Then the response status code should be 200
And the "count" property should equal 3
When I send an api request to get gorilla "@gorilla" basket
Then the response status code should be 200
And the "count" property should equal 0
When bonobo "@bonobo1" takes bananas "@banana1, @banana2" from the tree "@tree"
And bonobo "@bonobo1" gives banana "@banana1" to gorilla "@gorilla"
And I ask how many bananas are left in "@gorilla" basket
Then gorilla "@gorilla" should have 1 banana in his basket
When I send an api request to get gorilla "@gorilla" basket
Then the response status code should be 200
And the "count" property should equal 1
When I send an api request to get tree "@tree" details
Then the response status code should be 200
And the "count" property should equal 1
When bonobo "@bonobo2" takes banana "@banana3" from the tree "@tree"
Then the tree "@tree" should have 0 banana left
When I send an api request to get tree "@tree" details
Then the response status code should be 200
And the "count" property should equal 0
When bonobo "@bonobo2" gives bananas "@banana3" to gorilla "@gorilla"
Then gorilla "@gorilla" should have 2 bananas in his basket
When I send an api request to get gorilla "@gorilla" basket
Then the response status code should be 200
And the "count" property should equal 2
Basically I think being explicit is key and this should never happen:
When I add token "123" to this bucket
It should be
Given there is a token "@token" which has for value "123"
And there is a bucket "@bucket"
When I add token "@token" to bucket "@bucket"
Also, in regards to this:
/**
* @When bonobo gives this banana to :monkey
*
* @ScenarioStateArgument("scenarioBanana")
* @ScenarioStateArgument(name="scenarioBonobo", argument="bonobo")
*
* @param string $monkey
* @param string $scenarioBanana
* @param Bonobo $bonobo
*/
public function giveBananaToGorilla($monkey, $scenarioBanana, Bonobo $bonobo)
{
}
It could be:
/**
* @When a there is a bonobo :bonoboStoreKey named :name
*
* @ScenarioStateAutosave()
*
* @param string $bonobo
*/
public function thereIsABonoboNamed($bonoboStoreKey, $name)
{
$bonobo = new Bonobo($name);
return $bonobo;
}
/**
* @When bonobo :bonoboStoreKey gives banana :bananaStoreKey to gorilla :gorillaStoreKey
*
* @ScenarioStateAutoload()
*
* @param Banana $banana
* @param Bonobo $bonobo
* @param Gorilla $gorilla
*/
public function bonoboGivesBananaToGorilla(Bonobo $bonobo, Banana $banana, Gorilla $gorilla)
{
}
ScenarioStateAutosave would autosave the variables to the store based on what is returned
ScenarioStateAutoload would autoload the variables to the store based on the keys provided
I really like the idea behind this extension.
(Even though most of the time, if you are at Level 3 of the Richardson Maturity Model, you can use HATEOS & Hypermedia to follow
_linksbut this is not always possible - hence the necessity of a solution which your extension solves really well.)This discussion was very interesting to me and I think you guys are solving something important.
In regards to readability, I wonder if one might consider the following as on top of what was discussed, I think:
.featurefilesIt should be the same for the store.
How about using the gherkin language instead?
This would be more explicit, and would allow to identify the store keys easily. Now, we know all objects being stored start with
@(it could be any notation) but when reading the test, it is more readable and really takes on the power of your extension which is the ability to store stuff between contexts easily.You can then imagine the following when things get tricky:
Basically I think being explicit is key and this should never happen:
It should be
Also, in regards to this:
It could be:
ScenarioStateAutosavewould autosave the variables to the store based on what is returnedScenarioStateAutoloadwould autoload the variables to the store based on the keys provided