Skip to content
This repository was archived by the owner on Jul 29, 2022. It is now read-only.
This repository was archived by the owner on Jul 29, 2022. It is now read-only.

[Discussion] Using a more explicit syntax #36

@Sydney-o9

Description

@Sydney-o9

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions