What is the right approach for using FooContext
classes in behat?
What it is by the docs:
A simple mnemonic for context classes is: “testing features in a context”. (...), the way you will test those features pretty much depends on the context you test them in.
In the docs FeatureContext
seems for me only to be a dummy context file so that you can fast create a behat test.
The context class should be called FeatureContext. It’s a simple convention inside the Behat infrastructure. FeatureContext is the name of the context class for the default suite.
Its not saying me directly that it has to be a context file per feature.
The only real other examples in the docs are contexts like ApiContext
or WebContext
.
default:
suites:
web_features:
paths: [ %paths.base%/features/web ]
contexts: [ WebContext ]
api_features:
paths: [ %paths.base%/features/api ]
contexts: [ ApiContext ]
What i also found was a CommandFeature and another CommandLineProcessContext.
So if i have many features to test, a context file would blow up very fast.
Then i see a more likely a context file per feature example by Marco Pivetta using an Aggregate as Context.
Is it a good idea to have a single context file per feature foo.feature
? Or are context files thought to be environmental contexts like in the docs ApiContext
or WebContext
?
Usually I prefer to divide context and features as follows:
That way you'll end up with a single suite using more than one context but with all context divided with a single responsibility.
Quick example
Features
|--- User
|----- login.feature
|----- change_password.feature
|----- impersonate.feature
|----- ban.feature
|----- ...
|--- ...
|--- Order
|----- checkout.feature
|----- cancel.feature
...
Context
|--- User
|---- LoginContext
|---- ChangePasswordContext
|---- ImpersonateContext
|---- BanContext
|---- ...
|--- Order
|---- CheckoutContext
|---- CancelContext
Each suite is composed with many context (for example, every time you need to login to check a behavior, you'll include LoginContext
in your suite).
default:
suites:
suite_name:
paths:
- '%paths.base%/Path/To/Feature/File'
contexts:
- Path\To\Context\LoginContext
- Path\To\A\SecondContext
- ...
This approach has many advantages in terms of maintainability, intuitiveness and so on.
If you would like to have a more generic panoramic on this subject, you can check slides from my talk at Symfony day 2017 in Milan