Skip to main content

Opinionated mocking library for Python

Project description

Decoy logo

Decoy

Opinionated mocking library for Python

Usage guide and documentation

Decoy is a mocking library designed for effective and productive test-driven development in Python. If you want to use tests to guide the structure of your code, Decoy might be for you!

Decoy mocks are async/await and type-checking friendly. Decoy is heavily inspired by (and/or stolen from) the excellent testdouble.js and Mockito projects. The Decoy API is powerful, easy to read, and strives to help you make good decisions about your code.

Install

pip install decoy

Setup

Pytest setup

Decoy ships with its own pytest plugin, so once Decoy is installed, you're ready to start using it via its pytest fixture, called decoy.

# test_my_thing.py
from decoy import Decoy

def test_my_thing_works(decoy: Decoy) -> None:
    ...

Mypy setup

By default, Decoy is compatible with Python typing and type-checkers like mypy. However, stubbing functions that return None can trigger a type checking error during correct usage of the Decoy API. To suppress these errors, add Decoy's plugin to your mypy configuration.

# mypy.ini
plugins = decoy.mypy

Other testing libraries

Decoy works well with pytest, but if you use another testing library or framework, you can still use Decoy! You just need to do two things:

  1. Create a new instance of Decoy() before each test
  2. Call decoy.reset() after each test

For example, using the built-in unittest framework, you would use the setUp fixture method to do self.decoy = Decoy() and the tearDown method to call self.decoy.reset(). For a working example, see tests/test_unittest.py.

Basic Usage

This basic example assumes you are using pytest. For more detailed documentation, see Decoy's usage guide and API reference.

Decoy will add a decoy fixture to pytest that provides its mock creation API.

from decoy import Decoy

def test_something(decoy: Decoy) -> None:
    ...

!!! note

Importing the `Decoy` interface for type annotations is recommended, but optional. If your project does not use type annotations, you can simply write:

```python
def test_something(decoy):
    ...
```

Create a mock

Use decoy.mock to create a mock based on some specification. From there, inject the mock into your test subject.

def test_add_todo(decoy: Decoy) -> None:
    todo_store = decoy.mock(cls=TodoStore)
    subject = TodoAPI(store=todo_store)
    ...

See creating mocks for more details.

Stub a behavior

Use decoy.when to configure your mock's behaviors. For example, you can set the mock to return a certain value when called in a certain way using then_return:

def test_add_todo(decoy: Decoy) -> None:
    """Adding a todo should create a TodoItem in the TodoStore."""
    todo_store = decoy.mock(cls=TodoStore)
    subject = TodoAPI(store=todo_store)

    decoy.when(
        todo_store.add(name="Write a test for adding a todo")
    ).then_return(
        TodoItem(id="abc123", name="Write a test for adding a todo")
    )

    result = subject.add("Write a test for adding a todo")
    assert result == TodoItem(id="abc123", name="Write a test for adding a todo")

See stubbing with when for more details.

Verify a call

Use decoy.verify to assert that a mock was called in a certain way. This is best used with dependencies that are being used for their side-effects and don't return a useful value.

def test_remove_todo(decoy: Decoy) -> None:
    """Removing a todo should remove the item from the TodoStore."""
    todo_store = decoy.mock(cls=TodoStore)
    subject = TodoAPI(store=todo_store)

    subject.remove("abc123")

    decoy.verify(todo_store.remove(id="abc123"), times=1)

See spying with verify for more details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

decoy-2.5.0.tar.gz (34.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

decoy-2.5.0-py3-none-any.whl (46.8 kB view details)

Uploaded Python 3

File details

Details for the file decoy-2.5.0.tar.gz.

File metadata

  • Download URL: decoy-2.5.0.tar.gz
  • Upload date:
  • Size: 34.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for decoy-2.5.0.tar.gz
Algorithm Hash digest
SHA256 5888a351a70d150fe9b789511ecb08373169a58c5979dbc623a117b8868e37bf
MD5 55eba78167da75e696533573885dd4d4
BLAKE2b-256 6bfeda2d6aa6adbe71f574a38ed434bb568d261633148c4f841935771633019b

See more details on using hashes here.

Provenance

The following attestation bundles were made for decoy-2.5.0.tar.gz:

Publisher: ci.yml on mcous/decoy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file decoy-2.5.0-py3-none-any.whl.

File metadata

  • Download URL: decoy-2.5.0-py3-none-any.whl
  • Upload date:
  • Size: 46.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for decoy-2.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fb3af019087054201a4e979d9e0fba8d990ef0338ec8628f1ce23232944dbac5
MD5 39bb6e20fcbc6db13738485b1c767f02
BLAKE2b-256 abd01e71f18642dfd85c7d2d29b54bf4d89fbfb95437ff9c487f014fe1c0431c

See more details on using hashes here.

Provenance

The following attestation bundles were made for decoy-2.5.0-py3-none-any.whl:

Publisher: ci.yml on mcous/decoy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page