Data-driven, keyword-driven, and hybrid approaches describe how automated test data and actions are organized. Data-driven testing separates input and expectation variants from a shared algorithm. Keyword-driven testing expresses steps through domain-language commands. Hybrid testing combines these ideas where each provides practical value.
These are design approaches rather than mandatory framework generations. Moving ordinary test code into tables does not automatically improve clarity. What matters is whether the team can quickly add an example, diagnose a failure, and safely change behavior without learning a complex custom interpreter.
Data-driven: one algorithm, different examples
This approach works well when actions stay the same while inputs and expected results vary. For example, name-length validation can receive an empty string, one character, the boundary length, and an overlength value. Each dataset should have its own identity in the report.
Avoid parameterizing scenarios with different actions and conditions. Branches such as “log in first for this row, upload a file for that row” indicate artificial commonality. Several clear checks are preferable to one function controlled by a table of hidden behavior.
A standalone Pytest example
The teaching contract requires a name, after trimming surrounding spaces, to contain two to five characters inclusive. This is an exercise rule rather than a universal requirement for people's names. Save the code as test_name.py, install pytest, and run python -m pytest -v test_name.py.
import pytest
def valid_name(value):
return 2 <= len(value.strip()) <= 5
@pytest.mark.parametrize('value, expected', [
pytest.param('', False, id='empty'),
pytest.param('A', False, id='below-min'),
pytest.param('AB', True, id='min'),
pytest.param('ABCDE', True, id='max'),
pytest.param('ABCDEF', False, id='above-max'),
pytest.param(' AB ', True, id='trimmed'),
])
def test_name_rule(value, expected):
assert valid_name(value) is expectedExpect six independent results. Changing the upper boundary to four should make max show a specific violation. In a real project, import the application function rather than copying it: a duplicate implementation does not test production code.
Where to keep data
Small datasets are usually easiest to keep beside the test. Large static reference datasets can use JSON or another agreed format with an explicit schema. Review data alongside code, especially when expected values change.
An external table helps only with clear ownership and versioning. Without change history, yesterday's result becomes irreproducible. Moving secrets or personal data from code to a spreadsheet does not make them safer: tests need synthetic data and authorized environment credentials.
If a source contains more variants than a single run needs, define selection rules explicitly and save the chosen rows. Otherwise, the same commit runs under different unrecorded conditions, making comparisons meaningless. Data value comes from the boundary or risk it checks rather than file size.
Keyword-driven: a controlled action language
Keyword-driven testing defines vocabulary such as “create cart,” “apply coupon,” and “check total.” An executor maps each keyword to implementation. This can help domain specialists read scenarios if the vocabulary is stable and matches their working concepts.
Keywords such as click, type, and wait form a technical language rather than a business description. A table of these commands often repeats test code less expressively. It also requires argument validation, unknown-command diagnostics, and compatibility with older scenarios.
A practical vocabulary example
For a sample order, use a cart worth 10,000 and coupon SAVE10. The scenario prepares the cart, applies the coupon, and checks a total of 9,000. Each step should accept typed values and return an understandable result containing the cart identifier.
An unknown coupon should produce the contract-defined error and leave the total unchanged. This is a separate scenario rather than a special branch in “apply successfully.” If the executor computes the expected discount using the same formula as the application, a shared defect may go unnoticed.
Hybrid without unnecessary layers
A practical hybrid may combine ordinary test code, small business functions, and parameterized data. For example, one checkout task can use several valid addresses while invalid addresses are checked separately through the API. This does not require inventing a file format.
Add a DSL only after a concrete need emerges. First identify why the existing test language does not suit readers and authors. If the problem is poor names and overly long functions, another interpreter usually will not solve it.
Independence and diagnostics
Each example should prepare its own state and release resources. Iterating through rows inside one test is inferior to parameterization: the first exception hides remaining cases, and the report contains one result. Separate cases let you rerun the exact failing variant.
Give data meaningful IDs: expired-coupon is more useful than case-17. On failure, show inputs and expected and actual values while sanitizing sensitive information. For a large vocabulary, validate files before accessing the application: a keyword typo should not be discovered only after lengthy setup.
Common mistakes
A table often becomes a program with conditions, loops, and variables but lacks normal language tooling. The team then owns a second runtime requiring tests and documentation. Another mistake is generating thousands of combinations without a risk model and treating every one as useful coverage.
Distinguish missing data from an expected empty value. A blank cell, null, and an empty string may mean different things to an API. Define and validate the representation before execution so setup errors do not resemble product defects.
Choosing an approach
Use data-driven testing for identical algorithms with different examples. Keyword-driven testing is justified by a stable domain vocabulary, clear authorship, and resources to maintain the executor. A hybrid should combine useful elements while preserving simple diagnosis.
Judge success through change: a new example requires no complex logic, failures identify specific rules, and data is versioned. A good framework reduces team effort and preserves test meaning; it does not need the maximum number of architectural layers.