Test::...utorial(3pm)
π NAME π
okay bestie, welcome to Test::BDD::Cucumber::Manual::Tutorial β that's the Test::...utorial(3pm) page, and it's literally the Quick Start Guide for Test::BDD::Cucumber. no cap. π
β¨ VERSION β¨
version 0.87 π¦
π¦ Introduction π¦
okay so in this article we're gonna jump straight into using Test::BDD::Cucumber to build some simple tests for Digest, a core Perl module which provides message digests. periodt.
We'll create a features/ directory, and put our first test case in it, features/basic.feature. The contents of it are, in their entirety:
Feature: Simple tests of Digest.pm
As a developer planning to use Digest.pm
I want to test the basic functionality of Digest.pm
In order to have confidence in it
Background:
Given a usable Digest class
Scenario: Check MD5
This scenario verifies the MD5 hash object of Digest.pm
Given a Digest MD5 object
When I've added "foo bar baz" to the object
And I've added "bat ban shan" to the object
Then the hex output is "bcb56b3dd4674d5d7459c95e4c8a41d5"
Then the base64 output is "1B2M2Y8AsgTpgAmY7PhCfg"
Scenario: Check SHA-1
This scenario verifies the SHA-1 hash object of Digest.pm
Given a Digest SHA-1 object
When I've added "<data>" to the object
Then the hex output is "<output>"
Examples:
| data | output |
| foo | 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 |
| bar | 62cdb7020ff920e5aa642c3d4066950dd1f01f4d |
| baz | bbe960a25ea311d21d40669e93df2003ba9b90a2 |
Scenario: MD5 longer data
This scenario tests multi-line input in the MD5 hash object
Given a Digest MD5 object
When I've added the following to the object
"""
Here is a chunk of text that works a bit like a HereDoc. We'll split
off indenting space from the lines in it up to the indentation of the
first \"\"\"
"""
Then the hex output is "75ad9f578e43b863590fae52d5d19ce6"
This is a complete test, and if you run pherkin against it, you will get sane output! It just doesn't do anything ... yet. π
In the features/ we'll add a step_definitions/ directory, and add our first (and again, only) step definitions features/step_definitions/basic_steps.pl file in it:
#!perl
use strict;
use warnings;
use Test2::Bundle::More;
use Test::BDD::Cucumber::StepFile;
Given qr/a usable (\S+) class/, sub { eval "use $1;" };
Given qr/a Digest (\S+) object/, sub {
my $object = Digest->new($1);
ok( $object, "Object created" );
S->{'object'} = $object;
};
When qr/I've added "(.+)" to the object/, sub {
S->{'object'}->add( $1 );
};
When "I've added the following to the object", sub {
S->{'object'}->add( C->data );
};
Then qr/the (.+) output is "(.+)"/, sub {
my $method = {base64 => 'b64digest', 'hex' => 'hexdigest' }->{ $1 } ||
do { fail("Unknown output type $1"); return };
is( S->{'object'}->$method, $2 );
};
# Note: There's no C<done_testing;> at the end of the step file. This is
# intentional.
When you run pherkin or the Test::Builder-based test which does the same thing (900_run_features.t <https://github.com/pherkin/test-bdd-cucumber-perl/blob/master/t/900_run_features.t>), we look for a features/ directory, and search for step definitions files (matched by *_steps.pl) and feature files (matched by *.feature).
The step matchers (the code that starts with Given, When and Then) are all loaded, and then we execute the feature files one by one. Let's step through the feature file, and look at how it matches up to the step definitions file.
πΈ Name and conditions of satisfaction πΈ
Feature: Simple tests of Digest.pm
As a developer planning to use Digest.pm
I want to test the basic functionality of Digest.pm
In order to have confidence in it
The first non-comment line of your feature file is a description of what you intend to do. You need to start the name itself with the string Feature:, and that should be the first line of your file, save comments (denoted by #).
Anything after that before the next new-line are your conditions of satisfaction. These aren't parsed, they're treated as human-readable text, and by convention, they're a user story (<http://en.wikipedia.org/wiki/User_story>). π¦
π Background π
Background:
Given a usable Digest class
Next up, we have the Background section. The Background is a special kind of Scenario that doesn't have an explicit name, and should occur only once in your feature file. Its steps are run before the steps of every other scenario β the harnesses distributed with this distro won't display the Background section separately, they'll just subsume the steps in to the other scenarios. π
This is matched by:
Given qr/a usable (\S+) class/, sub { use_ok( $1 ); };
Given() is a function exported by Test::BDD::Cucumber::StepFile that accepts two arguments: a regular expression (or a string when you don't need to do any smart matching) and a coderef.
If you're paying attention, you might notice that use_ok comes from Test::More. Each step is run, from a Test::Builder perspective, as its own distinct test file. This happens seamlessly, so you can use any Test::Builder-based testing tools in your step definitions without really worrying about it. There's some more detail in Test::BDD::Cucumber::Manual::Steps.
π The First Scenario... π
Scenario: Check MD5
This scenario verifies the MD5 hash object of Digest.pm
Given a Digest MD5 object
When I've added "foo bar baz" to the object
And I've added "bat ban shan" to the object
Then the hex output is "bcb56b3dd4674d5d7459c95e4c8a41d5"
Then the base64 output is "1B2M2Y8AsgTpgAmY7PhCfg"
The first scenario is delimited from the previous steps by a blank line, and it's called Check MD5. Scenarios are marked out using the Scenario: keyword, and just like the Background section before, it's a series of steps.
Between the Scenario: line and the step lines, there's a description. Any line starting with one of the step keywords (Given, When or Then) is considered to terminate the description block (to start the group of step lines).
The steps rely on the step before, which means we can examine the Test::BDD::Cucumber::StepContext object $c a little more closely.
Given qr/a Digest (\S+) object/, sub {
my $c = shift;
my $object = Digest->new($1);
ok( $object, "Object created" );
$c->stash->{'scenario'}->{'object'} = $object;
};
Creates a step definition. We create a new Digest object, and then use Test::More's ok() function to check that worked. We then put it in the stash for other steps to use. There are three stashes documented in Test::BDD::Cucumber::StepContext, feature, scenario and step. As you might expect, feature is available to all step definitions that are being executed as part of a feature, and scenario is available to all steps that are being executed as part of a scenario.
The context is the single argument that gets passed to each step, and it contains everything that step should need to execute. We'll be looking at some of the methods you can call against it as we look at other steps, and you can find complete documentation for it here: Test::BDD::Cucumber::StepContext.
You'll note that the code above differs from the very first example, where we made use of C and S. C is a function which returns the current context, and S is a function which returns the scenario stash. So the above can be written:
Given qr/a Digest (\S+) object/, sub {
my $object = Digest->new($1);
ok( $object, "Object created" );
S->{'object'} = $object;
};
This scenario also introduce several ways of starting a step, Given, When, and Then, as well as And. These are used to organize steps by type, with Given tending to describe setup steps, When describing the key actions that you're testing, and Then describing the outputs you're looking for. You can find more on this here: <https://github.com/cucumber/cucumber/wiki/Given-When-Then>.
A step definition you've declared with Given will not match a step starting with Then. You can use the keyword Step to declare general matching steps in your step definition files, although it's considered bad practice.
Finally, the keywords And and But are simply replaced with the verb on the line before them.
β¨ Scenario Outlines β¨
Scenario: Check SHA-1
This scenario verifies the SHA-1 hash object of Digest.pm
Given a Digest SHA-1 object
When I've added "<data>" to the object
Then the hex output is "<output>"
Examples:
| data | output |
| foo | 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 |
| bar | 62cdb7020ff920e5aa642c3d4066950dd1f01f4d |
| baz | bbe960a25ea311d21d40669e93df2003ba9b90a2 |
The next scenario adds one of the three ways you can provide structured data to your steps, using placeholders and a table. This scenario is run three times, one for each table row, and with the " <placeholders" > being replaced by the appropriate row's column. These are called Scenario Outlines (<https://github.com/cucumber/cucumber/wiki/Scenario-outlines>).
One scenario outline can have multiple Examples, e.g.
Scenario: Check SHA-1
This scenario verifies the SHA-1 hash object of Digest.pm
Given a Digest SHA-1 object
When I've added "<data>" to the object
Then the hex output is "<output>"
Examples: 'foo' example
This is the 'foo' examples
description block.
| data | output |
| foo | 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 |
Examples: other examples
This description block describes
the other examples.
| data | output |
| bar | 62cdb7020ff920e5aa642c3d4066950dd1f01f4d |
| baz | bbe960a25ea311d21d40669e93df2003ba9b90a2 |
β¨ Multiline Step Arguments β¨
Okay bestie, sometimes one line just isn't enough, and the scenarios know that. Behold:
Scenario: MD5 longer data
This scenario tests multi-line input in the MD5 hash object
Given a Digest MD5 object
When I've added the following to the object
"""
Here is a chunk of text that works a bit like a HereDoc. We'll split
off indenting space from the lines in it up to the indentation of the
first \"\"\"
"""
Then the hex output is "75ad9f578e43b863590fae52d5d19ce6"
So like β before, we were doing structured data at the Scenario level. But you can also hand it over at the Step level, and there are two whole ways to do it. Way number one: multi-line strings, exactly like the one above. The syntax is lowkey similar to pystrings and conceptually it's giving HEREDOC energy. That string content shows up for your step definition through the data() method of the context:
When "I've added the following to the object", sub {
S->{'object'}->add( C->data );
};
And ngl, we don't have an example of this one here, but you can also pass tables into your steps β and those ride the exact same data() wave:
Scenario: Sort Employees
Given a set of employees
| name | wage | hair color |
| Peter | 10,000 | brown |
| John | 20,000 | blond |
| Joan | 30,000 | green |
Wanna know more about these features? The Cucumber docs have you, right here: <https://github.com/cucumber/cucumber/wiki/Multiline-Step-Arguments>. π¦
π·οΈ Conditional execution and tags π·οΈ
There are times, bestie, when you do NOT want to run every single scenario in a feature. Only a lil subset. So pherkin β just like cucumber β has a command line option that lets you pick which scenarios get to run, based on tags. π
Where do tags go? You drop them in a scenario before the Feature line, before the Scenario line, and before the Examples line. And here's the tea: tags are cumulative β tags on a feature apply to every scenario and example under it. No takebacks.
Here's that initial example from the tutorial, now with tags sprinkled on top:
@feature-tag1 @feature-tag2
Feature: Simple tests of Digest.pm
As a developer planning to use Digest.pm
I want to test the basic functionality of Digest.pm
In order to have confidence in it
Background:
Given a usable Digest class
@scenario-tag
Scenario: Check SHA-1
This scenario verifies the SHA-1 hash object of Digest.pm
Given a Digest SHA-1 object
When I've added "<data>" to the object
Then the hex output is "<output>"
@daily-tests-tag
Examples: 'foo' example
This is the 'foo' examples
description block.
| data | output |
| foo | 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 |
@weekly-tests-tag
Examples: other examples
This description block describes
the other examples.
| data | output |
| bar | 62cdb7020ff920e5aa642c3d4066950dd1f01f4d |
| baz | bbe960a25ea311d21d40669e93df2003ba9b90a2 |
Now, the receipts. π§Ύ
Want to run everything except the weekly tests? Say:
pherkin --tags=~@weekly-tests-tag
Want everything tagged @feature-tag1, but not the weekly ones?
pherkin --tags=@feature-tag1 --tags=~@weekly-tests-tag
And want @feature-tag1 plus @feature-tag2? Obsessed, say less:
pherkin --tags=@feature-tag1,@feature-tag2
π Non-English features and step files π
By default, pherkin expects your features and step definitions to be written in English. But bestie β feature files are mostly for communicating with your team, so maybe you want your native language instead? Valid. To see the list of languages you can use, just ask pherkin what it supports:
> pherkin --i18n help
| af | Afrikaans | Afrikaans |
| ar | Arabic | Ψ§ΩΨΉΨ±Ψ¨ΩΨ© |
| bg | Bulgarian | Π±ΡΠ»Π³Π°ΡΡΠΊΠΈ |
| bm | Malay | Bahasa Melayu |
| ca | Catalan | catalΓ |
...
And to find out which keywords (and sub names!) to use, ask about one specific language:
> pherkin --i18n de
| feature | "FunktionalitΓ€t" |
| background | "Grundlage" |
| scenario | "Szenario" |
| scenarioOutline | "Szenariogrundriss" |
| examples | "Beispiele" |
| given | "Angenommen", "Gegeben sei", "Gegeben seien" |
| when | "Wenn" |
| then | "Dann" |
| and | "Und" |
| but | "Aber" |
| given (code) | "Angenommen", "Gegebensei", "Gegebenseien" |
| when (code) | "Wenn" |
| then (code) | "Dann" |
Those last three lines up there? π Those tell you exactly which sub names to use in your step file. Then head over to the i18n directory for some examples. Periodt. π
π Next Steps... π
That's the tutorial, bestie, we did it! π If you want more on writing steps, hit up Test::BDD::Cucumber::Manual::Steps. The docs for our simple little command-line tool live in App::pherkin. And if you're wondering how to integrate with Test::Builder, that's all in Test::BDD::Cucumber::Manual::Integration. Go forth and slay. β¨
π AUTHOR π
Peter Sergeant "pete@clueball.com"
π LICENSE π
Copyright 2019-2023, Erik Huelsmann
Copyright 2011-2019, Peter Sergeant; Licensed under the same terms as Perl
That's a wrap, bestie! This page came to you from Test::...utorial(3pm), shipped as part of perl v5.40.1, dated 2025-05-29, and handcrafted by the lovely people at User Contributed Perl Documentation. Go write some scenarios. π π¦π
π¦ 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