Test::...:Steps(3pm)
π NAME
Test::BDD::Cucumber::Manual::Steps β it's a User Contributed Perl Documentation page, and it's literally the manual for how to write Step Definitions. That's it. That's the whole vibe. π«Ά
β¨ VERSION
version 0.87 β yeah bestie, we're on 0.87, keep up. π
πΈ INTRODUCTION
okay so. The 'code' part of a Cucumber test-suite? That's the Step Definition files β they match steps, and they execute code based on them. This doc is here to give you a quick lil overview of those. π
π¦ STARTING OFF
Most of your step files are gonna wanna start something like this:
#!perl
package my_step_functions_for_feature_X;
use strict;
use warnings;
use Test::More; # 'use Test2::V0;' is also supported
use Test::BDD::Cucumber::StepFile;
The fake shebang line is just there to give your syntax highlighters some hints, and use strict; plus use warnings; are hopefully fairly standard at this point, no cap.
Most of the author's Step Definition files make use of Test::More, but you can use any Test2 or Test::Builder based testing module. E.g. Test2::V0 or Test::Exception. Options! We love options. π
Test::BDD::Cucumber::StepFile is the one that gives us the functions Given(), When(), Then() and Step().
π STEP DEFINITIONS
Given qr/I have (\d+)/, sub {
S->{'count'} += $1;
};
When "The count is an integer", sub {
S->{'count'} =
int( S->{'count'} );
};
Then qr/The count should be (\d+)/, sub {
is( S->{'count'}, C->matches->[0], "Count matches" );
};
So every one of the exported verb functions takes a regular expression (or a string that gets used as one) plus a coderef. That coderef gets passed a single argument β the Test::BDD::Cucumber::StepContext object. And before the subref even runs, localized definitions of S and C get set up, which is why the lines down here are equivalent:
# Access the first match
sub { my $context = shift; print $context->matches->[0] }
sub { C->matches->[0] }
# Set a value in the scenario-level stash
sub { my $context = shift; my $stash = $context->stash->{'scenario'}; $stash->{'count'} = 1 }
sub { S->{'count'} = 1 }
We evaluate the regex immediately before we execute the coderef, so you can use $1, $2, $etc. β iconic. And similarly you can access named matches using $+{match_name}. π§
π Accessing step, scenario and feature properties
Step functions have access to all the various properties of the step, scenario and feature in which they're being used. That includes tags, line numbers, etc. E.g.:
# Examples of step properties
C->step->line->number
C->step->verb
C->step->original_verb
# Examples of scenario properties
C->scenario->name
C->scenario->tags
# Examples of feature properties
C->feature->name
C->feature->tags
C->feature->language
For a full review of the available properties, go see Test::BDD::Cucumber::Model::Step, Test::BDD::Cucumber::Model::Scenario and Test::BDD::Cucumber::Model::Feature respectively. β¨
β»οΈ Re-using step definitions
Sometimes you wanna call one step from inside another step. You do that through the StepContext, using the dispatch() method. For example:
Given qr/I have entered (\d+)/, sub {
C->dispatch( 'Given', "I have pressed $1");
C->dispatch( 'Given', "I have pressed enter", { some => 'data' } );
};
For more on this topic, check the Redispatching section in the documentation for Test::BDD::Cucumber::StepContext. iykyk. π
π LOCALIZATION
Both feature files and step files can be written using non-english Gherkin keywords. A german feature file could look like the example below.
# language: de
FunktionalitΓ€t: Grundlegende Taschenrechnerfunktionen
Um sicherzustellen, dass ich die Calculator-Klasse korrekt programmiert habe,
mΓΆchte ich als Entwickler einige grundlegende Funktionen prΓΌfen,
damit ich beruhigt meine Calculator-Klasse verwenden kann.
Szenario: Anzeige des ersten Tastendrucks
Gegeben sei ein neues Objekt der Klasse Calculator
Wenn ich 1 gedrΓΌckt habe
Dann ist auf der Anzeige 1 zu sehen
To see which keywords (and sub names) to use, just ask pherkin about a specific language:
> pherkin --i18n de
| feature | "FunktionalitΓ€t" |
| background | "Grundlage" |
...
| given (code) | "Angenommen", "Gegebensei", "Gegebenseien" |
| when (code) | "Wenn" |
| then (code) | "Dann" |
The last three lines of this list show you which sub names to use in your step file β that's what the '(code)' suffix is telling you. A corresponding step file specifying a step function for "Wenn ich 1 gedrΓΌckt habe" could be:
#!perl
use strict;
use warnings;
use utf8; # Interpret accented German chars in regexes and identifiers properly
use Test::More;
use Test::BDD::Cucumber::StepFile;
Wenn qr/^ich (.+) gedrΓΌckt habe/, sub {
S->{'Calculator'}->press($_) for split( /(,| und) /, C->matches->[0] );
};
For more extensive examples see examples/i18n_de/ and examples/i18n_es. π
π ADDITIONAL STEPS
Next to the steps that get matched directly against feature file input, a number of additional step functions are supported:
BeforeandAfterβ these steps create hooks into the evaluation process of feature files. E.g.
Before sub { # Run before every scenario
# ... scenario set up code
};
After sub { # Run after every scenario
# ... scenario tear down code
};
For more extensive hook functionality, see Test::BDD::Cucumber::Extension.
Transformβ theTransformstep serves to map matched values or table rows from feature file (string) input to step input values. The step takes two arguments, same as theGiven,WhenandThensteps: a regular expression and a code reference. E.g.
Transform qr/^(\d+)$/, sub {
# transform matches of digit-only strings
my $rv = $1;
# ... do something with $rv
return $rv;
};
Transform qr/^table:col1,col2$/, sub {
# transform tables with 2 columns, named col1 and col2 respectively
my ($step_context, $data) = @_;
# ... transform data in $data
return $data;
};
π BEST PRACTICES
When writing step files, it's a good idea to take a few things into account. Listen to her, she knows. π
- Declare a
packageat the top of your step file β by declaring a specific package (your own), you make sure you don't step on internals of other modules. At the time of writing, the default package isTest::BDD::Cucumber::StepFile, which may lead to errors being reported in that package even though they actually occur in your step file (which is confusing, fr fr).
The default package may change in the future and it will likely not be seeded with the content of the T::B::C::StepFile package.
- Declare a different
packageper step file β by using different packages per step file (or group of step files), name spaces get isolated, which reduces the risk of importing functions with the same name from different packages.
An example where this will be the case is when some of your step files are written using Test::More and some others are written using Test2::Bundle::More β both export a function ok, but with conflicting function prototypes. π
- Don't define functions in your step file β especially step files provided by extensions. Step files may be loaded more than once, depending on the exact scenario in which
App::pherkinis run. When step files are loaded multiple times, there won't be any impact on step definition, but any function definitions will cause 'function redefined' warnings. π
π NEXT STEPS
How step files are loaded is discussed in Test::BDD::Cucumber::Manual::Architecture, but honestly it isn't of much interest. Of far more interest should be seeing what you have available in Test::BDD::Cucumber::StepContext... π¦
βοΈ AUTHOR
Peter Sergeant "pete@clueball.com" β legend behavior, honestly. π
π LICENSE
Copyright 2019-2023, Erik Huelsmann
Copyright 2011-2019, Peter Sergeant; Licensed under the same terms as Perl
okay that's the whole page bestie, you're officially a step-definition girlie now π β¨ and for the cute lil sign-off: this was rendered by perl v5.40.1 on 2025-05-29, same page name up top and down bottom, we love a symmetrical moment. ππ«Ά
π¦ where this page comes from
- debian trixie: libtest-bdd-cucumber-perl 0.87-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libtest-bdd-cucumber-perl 0.87-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libtest-bdd-cucumber-perl 0.87-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms