DjangoRestFramework API checker
Project description
# DRF API Checker
[![pypi-version]][pypi] [![travis-png-m]][travis-l-m] [![codecov-badge]][codecov]
This module offers some utilities to avoid unwanted changes in Django Rest Framework responses,
so to keep stable contracts
The purpose is to guarantee that any code changes never introduce 'contract violations'
changing the Serialization behaviour.
Contract violations can happen when:
- fields are removed from Serializer
- field representation changes (ie. date/number format, )
- Response status code changes (optional)
- Response headers change (optional)
How it works:
-------------
First time the test run, the response and model instances are serialized and
saved on the disk; any further execution is checked against this first response.
Test data are saved in the same directory where the test module lives,
under `_api_checker/<module_fqn>/<test_class>`
Fields that cannot be checked by value (ie timestamps/last modified) can be tested writing
custom `assert_<field_name>` methods.
In case of nested objects, method names must follow the field "path".
(ie. `assert_permission_modified` vs `assert_modified`)
This module can also intercept when a field is added,
in this case it is mandatory recreate stored test data; simply delete them from the disk
or set `API_CHECKER_RESET` environment variable and run the test again,
in case something goes wrong the output will be
**Field values mismatch**
AssertionError: View `<class 'path.to.module.CustomerListAPIView'>` breaks the contract.
Field `name` does not match.
- expected: `Partner 0`
- received: `Partner 11`
**Field removed**
AssertionError: View `<class 'path.to.module.CustomerListAPIView'>` breaks the contract.
Field `id` is missing in the new response
**Field added**
AssertionError: View `<class 'path.to.module.CustomerListAPIView'>` returned more field than expected.
Action needed api_customers.response.json need rebuild.
New fields are:
`['country']`
How To use it:
--------------
**unittest**
Using ApiCheckerMixin::
class TestAPIAgreements(ApiCheckerMixin, TestCase):
def get_fixtures(self):
return {'customer': CustomerFactory()}
def test_customer_detail(self):
url = reverse("customer-detail", args=[self.get_fixture('customer').pk])
self.assertGET(url)
Using ApiCheckerBase metaclass
class TestAPIIntervention(TestCase, metaclass=ApiCheckerBase):
URLS = [
reverse("intervention-list"),
reverse("intervention-detail", args=[101]),
]
def get_fixtures(cls):
return {'intervention': InterventionFactory(id=101),
'result': ResultFactory(),
}
ApiCheckerBase can produce API test with minimum effort but it offers less flexibility
than ApiCheckerMixin.
**pytest**
pytest integraation is provided by two helpers `frozenfixture` and `contract`::
from django.urls import reverse
from drf_api_checker.pytest import contract, frozenfixture
@frozenfixture
def frozen_detail(db):
from demo.factories import DetailFactory
return DetailFactory()
@contract()
def test_url(frozen_detail):
url = reverse("master-list")
return url
Custom checks:
--------------
Sometimes it is not possible to check a field by value but exists anyway a mechanism
to check the contract (ie. `timestamp` field - _ignore for this example tools like [freezegun](https://github.com/spulec/freezegun)_)
To handle this situations you can write custom `Recorder` with specia `asserters`:
from drf_api_checker.recorder import Recorder
class TimestampRecorder(Recorder):
def assert_last_modify_date(self, response: Response, stored: Response, path: str):
value = response['last_modify_date']
assert datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ')
custom asserter is a method named `assert_<field_name>`, in case of nested serializers
you can have more specific asserter using `assert_<fk_field_name>_<field_name>`
Links
-----
|||
|--------------------|------------------------------------------------------------|
| Develop | [![travis-png-d]][travis-l-d]|
| Master | [![travis-png-m]][travis-l-m]|
| Project home page: | https://github.com/saxix/drf-api-checker |
| Issue tracker: | https://github.com/saxix/drf-api-checker/issues?sort |
| Download: | http://pypi.python.org/pypi/drf-api-checker/ |
| Documentation: | https://drf-api-checker.readthedocs.org/en/develop/ |
[travis-png-m]: https://secure.travis-ci.org/saxix/drf-api-checker.svg?branch=master
[travis-l-m]: https://travis-ci.org/saxix/drf-api-checker?branch=master
[travis-png-d]: https://secure.travis-ci.org/saxix/drf-api-checker.svg?branch=develop
[travis-l-d]: https://travis-ci.org/saxix/drf-api-checker?branch=develop
[codecov-badge]: https://codecov.io/gh/saxix/drf-api-checker/branch/develop/graph/badge.svg
[codecov]: https://codecov.io/gh/saxix/drf-api-checker
[pypi-version]: https://img.shields.io/pypi/v/drf-api-checker.svg
[pypi]: https://pypi-hypernode.com/project/drf-api-checker/
[![pypi-version]][pypi] [![travis-png-m]][travis-l-m] [![codecov-badge]][codecov]
This module offers some utilities to avoid unwanted changes in Django Rest Framework responses,
so to keep stable contracts
The purpose is to guarantee that any code changes never introduce 'contract violations'
changing the Serialization behaviour.
Contract violations can happen when:
- fields are removed from Serializer
- field representation changes (ie. date/number format, )
- Response status code changes (optional)
- Response headers change (optional)
How it works:
-------------
First time the test run, the response and model instances are serialized and
saved on the disk; any further execution is checked against this first response.
Test data are saved in the same directory where the test module lives,
under `_api_checker/<module_fqn>/<test_class>`
Fields that cannot be checked by value (ie timestamps/last modified) can be tested writing
custom `assert_<field_name>` methods.
In case of nested objects, method names must follow the field "path".
(ie. `assert_permission_modified` vs `assert_modified`)
This module can also intercept when a field is added,
in this case it is mandatory recreate stored test data; simply delete them from the disk
or set `API_CHECKER_RESET` environment variable and run the test again,
in case something goes wrong the output will be
**Field values mismatch**
AssertionError: View `<class 'path.to.module.CustomerListAPIView'>` breaks the contract.
Field `name` does not match.
- expected: `Partner 0`
- received: `Partner 11`
**Field removed**
AssertionError: View `<class 'path.to.module.CustomerListAPIView'>` breaks the contract.
Field `id` is missing in the new response
**Field added**
AssertionError: View `<class 'path.to.module.CustomerListAPIView'>` returned more field than expected.
Action needed api_customers.response.json need rebuild.
New fields are:
`['country']`
How To use it:
--------------
**unittest**
Using ApiCheckerMixin::
class TestAPIAgreements(ApiCheckerMixin, TestCase):
def get_fixtures(self):
return {'customer': CustomerFactory()}
def test_customer_detail(self):
url = reverse("customer-detail", args=[self.get_fixture('customer').pk])
self.assertGET(url)
Using ApiCheckerBase metaclass
class TestAPIIntervention(TestCase, metaclass=ApiCheckerBase):
URLS = [
reverse("intervention-list"),
reverse("intervention-detail", args=[101]),
]
def get_fixtures(cls):
return {'intervention': InterventionFactory(id=101),
'result': ResultFactory(),
}
ApiCheckerBase can produce API test with minimum effort but it offers less flexibility
than ApiCheckerMixin.
**pytest**
pytest integraation is provided by two helpers `frozenfixture` and `contract`::
from django.urls import reverse
from drf_api_checker.pytest import contract, frozenfixture
@frozenfixture
def frozen_detail(db):
from demo.factories import DetailFactory
return DetailFactory()
@contract()
def test_url(frozen_detail):
url = reverse("master-list")
return url
Custom checks:
--------------
Sometimes it is not possible to check a field by value but exists anyway a mechanism
to check the contract (ie. `timestamp` field - _ignore for this example tools like [freezegun](https://github.com/spulec/freezegun)_)
To handle this situations you can write custom `Recorder` with specia `asserters`:
from drf_api_checker.recorder import Recorder
class TimestampRecorder(Recorder):
def assert_last_modify_date(self, response: Response, stored: Response, path: str):
value = response['last_modify_date']
assert datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ')
custom asserter is a method named `assert_<field_name>`, in case of nested serializers
you can have more specific asserter using `assert_<fk_field_name>_<field_name>`
Links
-----
|||
|--------------------|------------------------------------------------------------|
| Develop | [![travis-png-d]][travis-l-d]|
| Master | [![travis-png-m]][travis-l-m]|
| Project home page: | https://github.com/saxix/drf-api-checker |
| Issue tracker: | https://github.com/saxix/drf-api-checker/issues?sort |
| Download: | http://pypi.python.org/pypi/drf-api-checker/ |
| Documentation: | https://drf-api-checker.readthedocs.org/en/develop/ |
[travis-png-m]: https://secure.travis-ci.org/saxix/drf-api-checker.svg?branch=master
[travis-l-m]: https://travis-ci.org/saxix/drf-api-checker?branch=master
[travis-png-d]: https://secure.travis-ci.org/saxix/drf-api-checker.svg?branch=develop
[travis-l-d]: https://travis-ci.org/saxix/drf-api-checker?branch=develop
[codecov-badge]: https://codecov.io/gh/saxix/drf-api-checker/branch/develop/graph/badge.svg
[codecov]: https://codecov.io/gh/saxix/drf-api-checker
[pypi-version]: https://img.shields.io/pypi/v/drf-api-checker.svg
[pypi]: https://pypi-hypernode.com/project/drf-api-checker/
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
drf-api-checker-0.4.1.tar.gz
(13.3 kB
view details)
File details
Details for the file drf-api-checker-0.4.1.tar.gz
.
File metadata
- Download URL: drf-api-checker-0.4.1.tar.gz
- Upload date:
- Size: 13.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.11.0 pkginfo/1.4.2 requests/2.18.4 setuptools/39.1.0 requests-toolbelt/0.8.0 tqdm/4.23.3 CPython/3.6.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | db4045afe4585120ab298464c37887d8567a0ecadbe8eaa6a0e348c364d745bb |
|
MD5 | 5c9d5804acc8cb6e0e68d7828a17b950 |
|
BLAKE2b-256 | 12dda93e1a320131eaab94fd9addb56138f7189a0575a8fd57c4b6ecea7b5a46 |