or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/pypi-ddt

Data-Driven/Decorated Tests - A library to multiply test cases

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/ddt@1.7.x

To install, run

npx @tessl/cli install tessl/pypi-ddt@1.7.0

index.mddocs/

DDT (Data-Driven Tests)

A Python library that allows you to multiply one test case by running it with different test data, making it appear as multiple test cases. DDT provides decorators that transform unittest test methods into data-driven tests, enabling systematic validation of functionality across diverse input conditions.

Package Information

  • Package Name: ddt
  • Package Type: pypi
  • Language: Python
  • Installation: pip install ddt
  • Documentation: http://ddt.readthedocs.org/

Core Imports

from ddt import ddt, data, file_data, unpack, idata, named_data, TestNameFormat

Or using the module directly:

import ddt

Basic Usage

import unittest
from ddt import ddt, data, file_data, unpack, TestNameFormat

@ddt
class MyTestCase(unittest.TestCase):
    
    @data(1, 2, 3, 4)
    def test_simple_values(self, value):
        self.assertTrue(value > 0)
    
    @data([1, 2], [3, 4], [5, 6])
    @unpack
    def test_with_unpack(self, a, b):
        self.assertLess(a, b)
    
    @file_data('test_data.json')
    def test_with_file_data(self, value):
        self.assertIsNotNone(value)

@ddt(testNameFormat=TestNameFormat.INDEX_ONLY)
class IndexOnlyTestCase(unittest.TestCase):
    
    @data("hello", "world")
    def test_with_index_only_names(self, value):
        self.assertIsInstance(value, str)

if __name__ == '__main__':
    unittest.main()

Capabilities

Class Decorator

ddt Decorator

Enables data-driven testing on unittest.TestCase subclasses.

def ddt(arg=None, **kwargs):
    """
    Class decorator for test cases that enables data-driven testing.
    
    Parameters:
    - arg: unittest.TestCase subclass or None (for parameterized decorator usage)
    - **kwargs: Optional configuration parameters
        - testNameFormat: TestNameFormat enum value for controlling test name generation
    
    Returns:
    Decorated test class with generated test methods
    """

Method Decorators

data Decorator

Provides test data values directly to test methods.

def data(*values):
    """
    Method decorator to provide test data values.
    
    Parameters:
    - *values: Variable number of test data values
    
    Returns:
    Decorated test method that runs once per data value
    """

idata Decorator

Provides test data from an iterable with optional index formatting.

def idata(iterable, index_len=None):
    """
    Method decorator to provide test data from an iterable.
    
    Parameters:
    - iterable: Iterable of test data values
    - index_len: Optional integer specifying width to zero-pad test indices
    
    Returns:
    Decorated test method that runs once per iterable item
    """

file_data Decorator

Loads test data from JSON or YAML files.

def file_data(value, yaml_loader=None):
    """
    Method decorator to load test data from files.
    
    Parameters:
    - value: Path to JSON/YAML file relative to test file directory
    - yaml_loader: Optional custom YAML loader function
    
    Returns:
    Decorated test method that runs with file-based data
    """

unpack Decorator

Unpacks tuple/list/dict test data as separate function arguments.

def unpack(func):
    """
    Method decorator to unpack structured test data.
    
    Parameters:
    - func: Test method to be decorated
    
    Returns:
    Decorated test method that unpacks data arguments
    """

named_data Decorator

Provides meaningful names to data-driven tests.

def named_data(*named_values):
    """
    Method decorator to provide named test data with meaningful test names.
    
    Parameters:
    - *named_values: Sequences or dictionaries with 'name' key for test identification
    
    Returns:
    Decorated test method with named test cases
    """

Utility Functions

mk_test_name Function

Generates test case names from original name, value, and index.

def mk_test_name(name, value, index=0, index_len=5, name_fmt=TestNameFormat.DEFAULT):
    """
    Generate a new name for a test case.
    
    Parameters:
    - name: Original test method name
    - value: Test data value
    - index: Test case index (default: 0)
    - index_len: Width for zero-padding indices (default: 5)
    - name_fmt: TestNameFormat enum value for name formatting
    
    Returns:
    str: Generated test case name
    """

is_trivial Function

Determines if a value is a simple/scalar type for name generation.

def is_trivial(value):
    """
    Check if value is a trivial type for test naming.
    
    Parameters:
    - value: Value to check
    
    Returns:
    bool: True if value is trivial (scalar or simple container)
    """

Configuration

TestNameFormat Enum

Controls how test names are generated.

class TestNameFormat(Enum):
    """
    Enum to configure test name composition.
    
    Values:
    - DEFAULT (0): Include both index and value in test name
    - INDEX_ONLY (1): Include only index in test name
    """
    DEFAULT = 0
    INDEX_ONLY = 1

Helper Classes

_NamedDataList Class

List subclass with name attribute for test naming (used internally by named_data).

class _NamedDataList(list):
    """
    List subclass with name attribute for meaningful test names.
    
    Parameters:
    - name: Name for the test case
    - *args: List elements
    """
    def __init__(self, name, *args): ...
    def __str__(self): ...

_NamedDataDict Class

Dict subclass with name attribute for test naming (used internally by named_data).

class _NamedDataDict(dict):
    """
    Dict subclass with name attribute for meaningful test names.
    
    Parameters:
    - **kwargs: Dictionary items including required 'name' key
    
    Raises:
    - KeyError: If 'name' key is not provided
    """
    def __init__(self, **kwargs): ...
    def __str__(self): ...

Constants

version

Package version string.

__version__ = "1.7.2"

Types

import unittest
from typing import Union, Any, List, Dict, Type, Callable

# Type aliases for documentation
TestData = Union[Any, List[Any], Dict[str, Any]]
TestMethod = Callable[..., None]
TestClass = Type[unittest.TestCase]

Usage Examples

Multiple Data Values

@ddt
class TestCalculator(unittest.TestCase):
    
    @data(2, 4, 6, 8)
    def test_even_numbers(self, value):
        self.assertEqual(value % 2, 0)

Complex Data with Unpacking

@ddt
class TestMath(unittest.TestCase):
    
    @data((2, 3, 5), (1, 1, 2), (0, 5, 5))
    @unpack
    def test_addition(self, a, b, expected):
        self.assertEqual(a + b, expected)

File-Based Data

# test_data.json
[
    {"input": "hello", "expected": 5},
    {"input": "world", "expected": 5}
]

@ddt
class TestStringLength(unittest.TestCase):
    
    @file_data('test_data.json')
    def test_length(self, value):
        input_str = value['input']
        expected = value['expected']
        self.assertEqual(len(input_str), expected)

Named Data for Better Test Names

@ddt
class TestAPI(unittest.TestCase):
    
    @named_data(
        ['valid_user', 'john@example.com', 200],
        ['invalid_email', 'invalid-email', 400],
        ['empty_email', '', 400]
    )
    def test_user_creation(self, email, expected_status):
        response = create_user(email)
        self.assertEqual(response.status_code, expected_status)

YAML Data with Custom Loader

import yaml

# Custom YAML loader for loading specific data types
class CustomLoader(yaml.SafeLoader):
    pass

def construct_custom_object(loader, node):
    return {'type': 'custom', 'value': loader.construct_scalar(node)}

CustomLoader.add_constructor('!custom', construct_custom_object)

@ddt
class TestYAMLData(unittest.TestCase):
    
    @file_data('test_data.yaml', yaml_loader=CustomLoader)
    def test_yaml_with_custom_loader(self, value):
        self.assertIn('type', value)
        self.assertEqual(value['type'], 'custom')

Example test_data.yaml file:

- !custom "test_value_1"
- !custom "test_value_2"
- !custom "test_value_3"