kgb
kgb is a Python library that provides utilities for creating function spies in unit tests, offering a powerful alternative to traditional mocking. It intercepts and records calls to functions, tracking arguments and return values, and can modify function behavior at the bytecode level. Unlike some mocking frameworks, kgb can spy on top-level functions in addition to class methods. It supports popular testing frameworks like unittest, pytest, nose, and nose2, and maintains an active release cadence, with recent versions adding support for the latest Python releases.
Common errors
-
ModuleNotFoundError: No module named 'kgb'
cause The 'kgb' library is not installed in your Python environment or the Python interpreter cannot find it in its search path.fixInstall the kgb library using pip: `pip install kgb` -
ImportError: cannot import name 'Spy' from 'kgb'
cause The 'Spy' class (or related components like 'SpyAgency') is not directly exposed under the top-level 'kgb' module; it resides in a submodule or needs to be imported differently.fixImport 'SpyAgency' (the primary way to manage spies) from the 'kgb' module: `from kgb import SpyAgency` -
AttributeError: 'function' object has no attribute 'spy'
cause This error typically occurs when using an older code style (pre-kgb 2.0) with a newer version of the kgb library. In older versions, spy methods were accessed via a '.spy' attribute (e.g., `my_func.spy.called`). kgb 2.0 and later versions made spy methods directly accessible on the spied function/method object itself (e.g., `my_func.called`).fixRemove the '.spy' attribute from your calls. For example, change `my_func.spy.called` to `my_func.called`, and `my_func.spy.assert_called_with()` to `my_func.assert_called_with()`. Alternatively, if using a `SpyAgency`, you'd use its assertion methods like `spy_agency.assert_spy_called(my_func)`.
Warnings
- breaking Version 7.0 dropped official support for Python 2.6, 3.4, and 3.5. Users on these Python versions must use `kgb` versions older than 7.0.
- deprecated CamelCase assertion methods (e.g., `assertSpyCalledWith`) are deprecated in favor of snake_case equivalents (e.g., `assert_spy_called_with`) for improved readability and consistency. While the old versions still exist, new code should use snake_case.
- breaking Prior to kgb 2.0, spying on standard functions required accessing a special `.spy` attribute (e.g., `func.spy.called_with()`), which was inconsistent with methods. This `.spy` attribute has been removed.
- gotcha Spying on methods wrapped in decorators that do not preserve the original function's name can cause errors. `kgb` will attempt to detect this and warn you.
Install
-
pip install kgb
Imports
- SpyAgency
from kgb import SpyAgency
- assert_spy_called_with
from kgb.asserts import assert_spy_called_with
Quickstart
import unittest
from kgb import SpyAgency, SpyOpReturn
class MyService:
def fetch_data(self, url):
# In a real application, this might make a network request
return f"Actual data from {url}"
class TestMyService(SpyAgency, unittest.TestCase):
def test_fetch_data_called_and_mocked(self):
service = MyService()
# Spy on the fetch_data method and make it return a mocked value
self.spy_on(service.fetch_data, op=SpyOpReturn("Mocked Data!"))
# Call the method that is now spied upon
result = service.fetch_data("https://example.com/api/v1/data")
# Assertions using kgb's spy capabilities
self.assertEqual(result, "Mocked Data!")
self.assert_spy_called(service.fetch_data)
self.assert_spy_called_with(service.fetch_data,
"https://example.com/api/v1/data")
# To run this example (typically done via a test runner like `python -m unittest`):
# if __name__ == '__main__':
# unittest.main()