A Leaner Approach with Vedro: Introducing Function-Based Scenarios

Nikita Tsvetkov
3 min readJan 25, 2025

--

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, and with 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:

  1. No Scope Support: Scope-related functionality is not supported because there is no underlying scenario instance to attach them to.
  2. No Step Function Decorators: Since steps (given, when, then) are not individual methods in vedro-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.

--

--

No responses yet