A Leaner Approach with Vedro: Introducing Function-Based Scenarios
One of the greatest strengths of Vedro is its scenario-based approach to testing. By modeling tests as clear-cut user stories, Vedro helps you write behavior-driven tests that reflect real-world usage. However, while scenario classes are fantastic for complex tests (like end-to-end scenarios), they can sometimes feel verbose when writing smaller, more straightforward checks, such as unit tests.
Why Scenario Classes Sometimes Feel Heavy
Here is a simple example of a Vedro scenario class decoding a base64-encoded string:
import base64
import vedro
class Scenario(vedro.Scenario):
subject = "decode base64 encoded string"
def given(self):
self.encoded = "YmFuYW5h"
def when(self):
self.decoded = base64.b64decode(self.encoded)
def then(self):
assert self.decoded == b"banana"
It’s certainly clear and descriptive, but for a small test like this, the class-based approach with separate methods can be a bit more than you need. This led us to develop vedro-fn: a plugin offering a concise, function-based syntax.
Introducing vedro-fn
With vedro-fn
, you can write the same test in a simpler, more streamlined style:
import base64
from vedro_fn import scenario, given, when, then
@scenario()
def decode_base64_encoded_str():
with given:
encoded = "YmFuYW5h"
with when:
decoded = base64.b64decode(encoded)
with then:
assert decoded == b"banana"
Notice how the Scenario
class has been replaced with a single decorated function. The steps (given
, when
, then
) are represented by context blocks rather than class methods. This is particularly convenient for tests that don’t need a full scenario class structure.
Key points:
- Just add
@scenario()
to any function. - Inside the function, use
with given
,with when
, andwith then
blocks to define your test flow. - Everything else works as you’d expect in Vedro: reporting, command line usage, test discovery, etc.
Installation
Just run:
$ vedro plugin install vedro-fn
And that’s it! You can now import and use the @scenario
, given
, when
, and then
blocks as shown above.
Using Additional Vedro Features
Reusing Scenario Decorators
In standard Vedro, you can decorate your scenario classes with @skip
, @only
, and other scenario-level decorators. With vedro-fn
, you can do the same by passing them as arguments to @scenario
:
import base64
from vedro import skip
from vedro_fn import scenario, given, when, then
@scenario[skip]()
def decode_base64_encoded_str():
with given:
encoded = "YmFuYW5h"
with when:
decoded = base64.b64decode(encoded)
with then:
assert decoded == b"banana"
This function is now skipped by the test runner, exactly like a skipped scenario class.
Parametrizing Your Tests
Need to test a variety of inputs and expected outputs? Parametrization works almost the same way it does in standard Vedro — just pass a list of params
to the @scenario()
decorator:
import base64
from vedro import params
from vedro_fn import scenario, when, then
@scenario([
params("YmFuYW5h", b"banana"),
params("", b""),
])
def decode_base64_encoded_str(encoded, expected):
with when:
decoded = base64.b64decode(encoded)
with then:
assert decoded == expected
This will generate separate test cases for each set of parameters passed in.
Limitations
While vedro-fn
provides nearly all the features you know and love from Vedro, there are a couple of caveats:
- No Scope Support: Scope-related functionality is not supported because there is no underlying scenario instance to attach them to.
- No Step Function Decorators: Since steps (
given
,when
,then
) are not individual methods invedro-fn
but rather code blocks within a function, you cannot decorate them separately.
Despite these limitations, everything else — various reporters, parallel execution, external plugins — works seamlessly with vedro-fn
.
Share Your Feedback!
vedro-fn
is an experimental plugin. If you find it helpful for tidying up smaller tests or want to see more functionality added, let us know! Your feedback will determine whether `vedro-fn` becomes a fully supported part of the Vedro core.