Configuring Test Suites¶
We already talked about configuring multiple contexts for a single testsuite in aprevious chapter. Now it istime to talk about test suites themselves. A test suite represents a group ofconcrete features together with the information on how to test them.
With suites you can configure Behat to test different kinds of featuresusing different kinds of contexts and doing so in one run. Test suites arereally powerful andbehat.yml makes them that much more powerful:
<?php// behat.phpuseApp\Tests\Behat\Context\AdminContext;useApp\Tests\Behat\Context\CoreDomainContext;useApp\Tests\Behat\Context\UserContext;useBehat\Config\Config;useBehat\Config\Config\Filter\RoleFilter;useBehat\Config\Profile;useBehat\Config\Suite;$profile=newProfile('default')->withSuite(newSuite('core_features')->withPaths('%paths.base%/features/core')->withContexts(CoreDomainContext::class))->withSuite(newSuite('user_features')->withFilter(newRoleFilter('user'))->withPaths('%paths.base%/features/web')->withContexts(UserContext::class))->withSuite(newSuite('admin_features')->withFilter(newRoleFilter('admin'))->withPaths('%paths.base%/features/web')->withContexts(AdminContext::class));returnnewConfig()->withProfile($profile);
Note
On PHP < 8.4, you need to wrap new invocations with parentheses before calling config object methods.
// ...// $profile = new Profile('default')$profile=(newProfile('default'))->withSuite(// new Suite('core_features')(newSuite('core_features'))->withPaths('%paths.base%/features/core')->withContexts(CoreDomainContext::class))// ...
Suite Paths¶
One of the most obvious settings of the suites is thepathsconfiguration:
<?php// behat.phpuseBehat\Config\Config;useBehat\Config\Profile;useBehat\Config\Suite;$profile=newProfile('default')->withSuite(newSuite('core_features')->withPaths('%paths.base%/features','%paths.base%/test/features','%paths.base%/vendor/.../features',));return(newConfig())->withProfile($profile);
As you might imagine, this option tells Behat where to search for test features.You could, for example, tell Behat to look into thefeatures/web folder for features and test them withWebContext:
<?php// behat.phpuseApp\Tests\Behat\Context\WebContext;useBehat\Config\Config;useBehat\Config\Profile;useBehat\Config\Suite;$profile=newProfile('default')->withSuite(newSuite('web_features')->withPaths('%paths.base%/features/web')->withContexts(WebContext::class));returnnewConfig()->withProfile($profile);
You then might want to also describe some API-specific features infeatures/api and test them with an API-specificApiContext. Easy:
<?php// behat.phpuseApp\Tests\Behat\Context\ApiContext;useApp\Tests\Behat\Context\WebContext;useBehat\Config\Config;useBehat\Config\Profile;useBehat\Config\Suite;$profile=newProfile('default')->withSuite(newSuite('web_features')->withPaths('%paths.base%/features/web')->withContexts(WebContext::class))->withSuite(newSuite('api_features')->withPaths('%paths.base%/features/api')->withContexts(ApiContext::class));returnnewConfig()->withProfile($profile);
This will cause Behat to:
Find all features inside
features/weband test them using yourWebContext.Find all features inside
features/apiand test them using yourApiContext.
Note
%paths.base% is a special variable inbehat.yml that refersto the folder in whichbehat.yml is stored. When using it, orany other percent-encased variable, it has to be put in quotes.
Path-based suites are an easy way to test highly-modular applicationswhere features are delivered by highly decoupled components. With suitesyou can test all of them together.
Suite Filters¶
In addition to being able to run features from different directories,we can run scenarios from the same directory, but filtered by specificcriteria. The Gherkin parser comes bundled with a set of cool filterssuch astags andname filters. You can use these filters to runfeatures with specific tag (or name) in specific contexts:
<?php// behat.phpuseApp\Tests\Behat\Context\ApiContext;useApp\Tests\Behat\Context\WebContext;useBehat\Config\Config;useBehat\Config\Filter\TagFilter;useBehat\Config\Profile;useBehat\Config\Suite;$profile=newProfile('default')->withSuite(newSuite('web_features')->withFilter(newTagFilter('@web'))->withPaths('%paths.base%/features')->withContexts(WebContext::class))->withSuite(newSuite('api_features')->withFilter(newTagFilter('@api'))->withPaths('%paths.base%/features')->withContexts(ApiContext::class));returnnewConfig()->withProfile($profile);
This configuration will tell Behat to run features and scenariostagged as@web inWebContext and features and scenariostagged as@api inApiContext. Even if they all are storedin the same folder. How cool is that? But it gets even better,because Gherkin 4+ (used in Behat 3+) added a very specialrolefilter. That means, you can now have nice actor-based suites:
<?php// behat.phpuseApp\Tests\Behat\Context\AdminContext;useApp\Tests\Behat\Context\UserContext;useBehat\Config\Config;useBehat\Config\Filter\RoleFilter;useBehat\Config\Profile;useBehat\Config\Suite;$profile=newProfile('default')->withSuite(newSuite('user_features')->withFilter(newRoleFilter('user'))->withPaths('%paths.base%/features')->withContexts(UserContext::class))->withSuite(newSuite('api_features')->withFilter(newRoleFilter('admin'))->withPaths('%paths.base%/features')->withContexts(AdminContext::class));return(newConfig())->withProfile($profile);
A Role filter takes a look into the feature description block:
Feature: Registering users In order to help more people use our system As an admin I need to be able to register more users
It looks for aAsa... orAsan... pattern and guesses itsactor from it. It then filters features that do not have the expectedactor from the set. In the case of our example, it basically means thatfeatures described from the perspective of theuser actor willbe tested inUserContext and features described from theperspective of theadmin actor will be tested inAdminContext.Even if they are in the same folder.
While it is possible to specify filters as part of suite configuration,sometimes you will want to exclude certain scenarios across the suite, with theoption to override the filters at the command line.
This is achieved by specifying the filter in the gherkin configuration:
<?php// behat.phpuseBehat\Config\Config;useBehat\Config\Filter\TagFilter;useBehat\Config\Profile;$profile=newProfile('default')->withFilter(newTagFilter('~@wip'));returnnewConfig()->withProfile($profile);
In this instance, scenarios tagged as @wip will be ignored unless the CLIcommand is run with a custom filter, e.g.:
vendor/bin/behat--tags=wipTip
More details on identifying tests can be found in the chapterIdentifying Tests.
Suite Contexts¶
Being able to specify a set of features with a set of contexts forthese features inside the suite has a very interesting side-effect.You can specify the same features in two different suites being testedagainst different contextsor the same contexts configured differently.This basically means that you can use the same subset of features todevelop different layers of your application with Behat:
<?php// behat.phpuseApp\Tests\Behat\Context\DomainContext;useApp\Tests\Behat\Context\WebContext;useBehat\Config\Config;useBehat\Config\Filter\TagFilter;useBehat\Config\Profile;useBehat\Config\Suite;$profile=newProfile('default')->withSuite(newSuite('domain_features')->withPaths('%paths.base%/features')->withContexts(DomainContext::class))->withSuite(newSuite('web_features')->withFilter(newTagFilter('@web'))->withPaths('%paths.base%/features')->withContexts(WebContext::class));returnnewConfig()->withProfile($profile);
In this case, Behat will first run all the features from thefeatures/folder inDomainContext and then only those tagged with@web inWebContext.
Tip
It might be worth reading how toexecute a specificsuite orinitialize a newsuite
Behat