Behat 3 - Communication between contexts

Created on 17 Jun 2014  路  18Comments  路  Source: Behat/Behat

Hello world ! :)

I am still exploring the huge potential of Behat 3 and got a new question about contexts.

On Behat 2, I was used to have a main FeatureContext which used many SubContexts. Then I was able to access/change class (context) methods/properties from other classes with :

$this->getMainContext()->getSubcontext('subcontext_alias')->some_method();

From now, on Behat 3, the new doc says :

Basically, all contexts under contexts section of your behat.yml are the same for Behat. It will find and use methods in them same way it does in default FeatureContext.

So if I have :

behat.yml

# behat.yml
contexts:
    - HelloContext
    - WorldContext

HelloContext

# HelloContext.php
<?php
use Behat\Behat\Context\SnippetAcceptingContext;

class HelloContext implements SnippetAcceptingContext
{
     public $greetings = "Hello";
}

What should I do to be able to access and modify $greetings from WorldContext ?

WorldContext

# WorldContext.php
<?php
use Behat\Behat\Context\Context;

class WorldContext implements Context
{
     public function changeGreetings(){
          // On Behat 2, I was doing 
          // $this->getMainContext()->getSubContext("HelloContext")->greetings .= " World !";
     }
}

Thanks !

Most helpful comment

While working on my idea yesterday evening, I discovered that there is a much better way to do this, without any extra Behat extension: https://gist.github.com/stof/930e968829cd66751a3a

I will submit a PR to the doc with this

All 18 comments

It seems that such system is not possible anymore (or if yes, please inform us in that topic !).

A workaround is to create a singleton class which have static fields and methods that could be callable from other context. It works well for a kind of MemoryClass which holds data you need in other contexts.

Also the Behat Page Extension seems very promising in regrouping functions into Page objects that could be reuse in code. Check it out here : http://extensions.behat.org/page-object/

Thanks to @norzechowicz for all the ideas and help !

As I told you, this singleton is a "hack" and you use it on your own risk. IMO you should not use one context in another because things might have different meaning for them. Its very easy to make a mess this way in your test suite.
Anyway PageObjectExtension should solve your problems :beer:

Indeed, the PageObjectExtension looks promising.

As for the singleton hack, for know it is a necessary hack as we need some data to be shared across all contexts during our tests. It's still better than a non-working app !

I would second the ability to have inter-context communications.

The usecase is the following:

  • in the testsuite we have different Context classes. Some are related to the pages being tested (proper "feature Contexts"), some are more generic in nature (handling debug logs, saving screenshots, sending notifications, setting up environment etc). We might call them "helper contexts"
  • in fact helper contexts might not even be created as Contexts at all. The thing is, they often need to have some initialization/cleanup done at specific points of the execution process, and making them Contexts which use the Behat hooks via tagged methods is the easiest way to achieve this (maybe it could also be achieved by creating a behat extension and using directly Symfony events listeners? Even if it is, it sounds like a lot of work)
  • this results in the feature context needing to access the helper context to execute some stuff

At the moment the codebase resorts to making most methods in helper contexts static methods, and putting a huge amount of current-state information in a singleton class.
But that feels bad.

Instead of making every context a singleton on its own, I was thinking of binding them to a context-pool via creation of an extension and letting the helper contexts expose an Interface, say

interface shareableContext
    public function shareMe($callable)
    {
        $callable($this);
    }

This might be in the end just a more convoluted way of doing what we do already with all our static methods...

Apropos PageObject: I am so far not convinced of its benefits. It seems overkill most of the time. Plus it does not directly address my needs.
The long story:
a) The tests I have seen written end up in feature steps which read _given I test that the functionality X works_, which removes imho all the advantages bdd has over say unit tests, as only the coder knows what is going on, and the product manager can not read nor write features
b) the way the pageObject class itself works is a bit counterintuitive vs. the http navigation flow (dev can create a pageObject without navigating to it and viceversa)
c) most tests end up split in 3 parts: the feature file, the context and the pageObject. This makes it hard to write and understand them

Have you guys find out how to use access data between contexts.
I am in the middle of upgrading to behat 3 and this is a big problem for us.

Steps like: i_click_on() are used in mostly all context. If I use trait, then it fails with duplicate step error.

Appreciate any help here :)

@rajeshtaneja I will try to post a gist of the work I have done

I have an idea about how to build this. I will try to build an extension for this during the weekend (maybe earlier if I have time for it)

Thanks Christophe and Gaetano ,

It will be very helpful, if I can get some clue on how to re-arrange my contexts. I looked at pageObject and I think that is an overkill. We have all basic functions like i_login_as(), i_have_following_users() etc. and they need to be part of mostly every context. The list is too big and it comes from different part of code. In behat 2.x it was used as sub-context, so that was not a problem, but not context being isolated is making me think what is the best way to re-arrange them.

I can create a new context object in my current context and set mink to call steps from diffent context, but saying so, this is messy way and (To be frank) I am not sure if that is the right way.

Cheers.

@stof tell me if you need any help!

Here's the gist https://gist.github.com/gggeek/f7a27006b9861ec841b9

Sorry if it is not fully usable as-is (you have to make a behat extension out of it, plus it does not contain examples of contexts sharing each other), but it should be understandable to people who grok behat

Thanks Gaetano,

This is a good way to share context, just wondering how step definition list be populated. Anyway will try apply this design to see if I can get anywhere.

While working on my idea yesterday evening, I discovered that there is a much better way to do this, without any extra Behat extension: https://gist.github.com/stof/930e968829cd66751a3a

I will submit a PR to the doc with this

@stof I had found out that possibility, but did not go that way because I did not want to litter my behat.yml with a lot of contexts declared in every suite (in fact the tests I was given had many such 'supporting' contexts in each suite, and I tried to remove as many as possible).

But I might have missed something. Is it f.e. possible to declare some contexts only once in a way that they apply to each suite anyway?

@gggeek This issue is about having a way to communicate between contexts, so I don't understand your comment saying you don't want multiple contexts. If you don't have multiple contexts, you are simply not concerned about the issue of communicating between them.

@RynnHeldeD I suggest keeping this closed in favor of the solution I suggested above (and for which I sent a documentation PR)

Alright, as there was some discussion, I thought it would be pertinent to reopen, sorry.

@stof you are right. My comment was not meant as a NACK, rather as an explanation of the rationale behind the different approach I had taken, so fine with me with the docs approach.

For the record, the contexts I wanted to eliminate from behat.yml were context with purely 'support' functionality - I agree that for the common case you'd want communication to happen between contexts which are declared as part of a suite because they do fully 'belong' there.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iongion picture iongion  路  8Comments

acoulton picture acoulton  路  5Comments

diamondsea picture diamondsea  路  6Comments

RusHiiii picture RusHiiii  路  6Comments

blixit picture blixit  路  8Comments