![Alt text](resources/drf-api-action-banner-current.png?raw=true "")
[![codecov](https://codecov.io/gh/Ori-Roza/drf-api-action/graph/badge.svg?token=2PB7NG8A4W)](https://codecov.io/gh/Ori-Roza/drf-api-action)
[![python - 3.8 | 3.9 | 3.10 | 3.11](https://img.shields.io/badge/python-3.8_|_3.9_|_3.10_|_3.11-blue)](https://)[![CI](https://github.com/Ori-Roza/drf-api-action/actions/workflows/tests.yaml/badge.svg?branch=master)](https://github.com/Ori-Roza/drf-api-action/actions/workflows/tests.yaml)
[![license - MIT](https://img.shields.io/badge/license-MIT-yellow)](https://)
The drf-api-action Python package is designed to elevate your testing experience for Django Rest Framework (DRF) REST endpoints.
With the api_action fixture, this package empowers you to effortlessly test your REST endpoints as if they were conventional functions.
Features:
* **Simplified Testing:** Testing DRF REST endpoints using the api_action plugin, treating them like regular functions.
* **Seamless Integration:** you don't need to do anything in existing server code.
* **Easy Debugging:** Instead of getting a response with error code by using default drf testing `client` object , get the real traceback that led to the error.
* **Pagination Support**: Paginating easily through pages by using `page` argument.
## Installation
You can install `drf-api-action` using pip:
```shell
pip install drf-api-action
```
## Usage
### To use `drf-api-action` as a Pytest fixture, you need to follow these steps:
#### Step 1: Import your Viewsets explicitly:
```python
import pytest
from tests.test_server.test_app.models import DummyModel
from tests.test_server.test_app.views import DummyViewSetFixture
```
#### Step 2: use the following action_api mark decorator:
`@pytest.mark.api_action(view_set_class={YOUR VIEW_SET})`
e.g:
our ViewSet is called `DummyViewSetFixture`
```python
import pytest
from tests.test_server.test_app.views import DummyViewSetFixture
@pytest.mark.api_action(view_set_class=DummyViewSetFixture)
def test_call_as_api_fixture(db, api_action):
pass
```
Now you can use all `DummyViewSetFixture` functionality!
#### Step 3: write your tests
e.g:
our ViewSet is called `DummyViewSetFixture`
```python
import pytest
from tests.test_server.test_app.models import DummyModel
from tests.test_server.test_app.views import DummyViewSetFixture
@pytest.mark.api_action(view_set_class=DummyViewSetFixture)
def test_call_as_api_fixture(db, api_action):
dummy_model = DummyModel()
dummy_model.dummy_int = 1
dummy_model.save()
res = api_action.api_dummy(pk=1)
assert res["dummy_int"] == 1
```
Here as an example, the real exception and trace will be thrown, make it easy to understand what the issue is:
```python
import pytest
from tests.test_server.test_app.views import DummyViewSetFixture
@pytest.mark.api_action(view_set_class=DummyViewSetFixture)
def test_dummy(db, api_action):
result = api_action.dummy(pk='bbb')
assert result['dummy_int'] == 1
```
```shell
tests/functionality_tests/test_as_api.py:11 (test_call_as_api)
self = <django.db.models.fields.BigAutoField: id>, value = 'bb'
def get_prep_value(self, value):
value = super().get_prep_value(value)
if value is None:
return None
try:
> return int(value)
E ValueError: invalid literal for int() with base 10: 'bb'
../venv/lib/python3.9/site-packages/django/db/models/fields/__init__.py:2053: ValueError
The above exception was the direct cause of the following exception:
queryset = <QuerySet [<DummyModel: DummyModel object (1)>]>, filter_args = ()
filter_kwargs = {'pk': 'bb'}
def get_object_or_404(queryset, *filter_args, **filter_kwargs):
"""
Same as Django's standard shortcut, but make sure to also raise 404
if the filter_kwargs don't match the required types.
"""
try:
> return _get_object_or_404(queryset, *filter_args, **filter_kwargs)
../venv/lib/python3.9/site-packages/rest_framework/generics.py:19:
....
....
...
```
Call endpoints with pagination:
```python
@pytest.mark.api_action(view_set_class=DummyAPIViewSet)
def test_pagination_data(db, api_action):
for i in range(1, 3):
dummy_model = DummyModel()
dummy_model.dummy_int = 1
dummy_model.save()
response = api_action.by_dummy_int(dummy_int=1, page=1)
obj = response['results'][0]
assert obj['dummy_int'] == 1
assert extract_page_number(response['next']) == 2
response = api_action.by_dummy_int(dummy_int=1, page=2)
assert extract_page_number(response['previous']) == 1
assert extract_page_number(response['next']) is None
```
## Package Testing
The `drf-api-action` library includes tests to ensure the functionality works as expected. To run the tests run `pytest`:
```shell
pytest
```
The tests will be executed, and the results will be displayed in the console.
## Example
Example of using drf-api-action in a [DRF project](https://github.com/Ori-Roza/drf-api-action-example)
## Support & Contribution
For guidance on support & contribution, see the [contributing guidelines](https://github.com/Ori-Roza/drf-api-action/blob/master/docs/CONTRIBUTING.md).
## Bug Report
For guidance on how to open a bug, see the [bug report template](https://github.com/Ori-Roza/drf-api-action/blob/master/docs/BUG_REPORT.md).
## Open an Issue
For guidance on how to open an issue, see the [issue template](https://github.com/Ori-Roza/drf-api-action/blob/master/docs/ISSUE_TEMPLATE.md).
## Code Of Conduct
[code of conduct](https://github.com/Ori-Roza/drf-api-action/blob/master/docs/CODE_OF_CONDUCT.md).
Raw data
{
"_id": null,
"home_page": "https://github.com/Ori-Roza/drf-api-action",
"name": "drf-api-action",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.7",
"maintainer_email": null,
"keywords": "pytest, mocks, testing, fixtures, tests, django",
"author": "Ori Roza",
"author_email": "ori75660@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/13/48/5ef3f92d8ccf8ac9b1e0c094466f52744a6cca6f68e76ddd337bf6415355/drf_api_action-1.2.2.tar.gz",
"platform": null,
"description": "![Alt text](resources/drf-api-action-banner-current.png?raw=true \"\")\n\n[![codecov](https://codecov.io/gh/Ori-Roza/drf-api-action/graph/badge.svg?token=2PB7NG8A4W)](https://codecov.io/gh/Ori-Roza/drf-api-action)\n[![python - 3.8 | 3.9 | 3.10 | 3.11](https://img.shields.io/badge/python-3.8_|_3.9_|_3.10_|_3.11-blue)](https://)[![CI](https://github.com/Ori-Roza/drf-api-action/actions/workflows/tests.yaml/badge.svg?branch=master)](https://github.com/Ori-Roza/drf-api-action/actions/workflows/tests.yaml)\n[![license - MIT](https://img.shields.io/badge/license-MIT-yellow)](https://)\n\n\nThe drf-api-action Python package is designed to elevate your testing experience for Django Rest Framework (DRF) REST endpoints.\nWith the api_action fixture, this package empowers you to effortlessly test your REST endpoints as if they were conventional functions.\n\nFeatures:\n\n* **Simplified Testing:** Testing DRF REST endpoints using the api_action plugin, treating them like regular functions.\n\n* **Seamless Integration:** you don't need to do anything in existing server code.\n\n* **Easy Debugging:** Instead of getting a response with error code by using default drf testing `client` object , get the real traceback that led to the error.\n\n* **Pagination Support**: Paginating easily through pages by using `page` argument.\n\n\n## Installation\n\nYou can install `drf-api-action` using pip:\n\n```shell\npip install drf-api-action\n```\n\n## Usage\n\n### To use `drf-api-action` as a Pytest fixture, you need to follow these steps:\n\n#### Step 1: Import your Viewsets explicitly:\n\n```python\nimport pytest\nfrom tests.test_server.test_app.models import DummyModel\nfrom tests.test_server.test_app.views import DummyViewSetFixture\n```\n\n#### Step 2: use the following action_api mark decorator:\n\n`@pytest.mark.api_action(view_set_class={YOUR VIEW_SET})`\n\ne.g:\nour ViewSet is called `DummyViewSetFixture`\n\n```python\nimport pytest\nfrom tests.test_server.test_app.views import DummyViewSetFixture\n\n\n@pytest.mark.api_action(view_set_class=DummyViewSetFixture)\ndef test_call_as_api_fixture(db, api_action):\n pass\n```\nNow you can use all `DummyViewSetFixture` functionality!\n\n#### Step 3: write your tests\n\ne.g:\nour ViewSet is called `DummyViewSetFixture`\n\n```python\nimport pytest\nfrom tests.test_server.test_app.models import DummyModel\nfrom tests.test_server.test_app.views import DummyViewSetFixture\n\n\n@pytest.mark.api_action(view_set_class=DummyViewSetFixture)\ndef test_call_as_api_fixture(db, api_action):\n dummy_model = DummyModel()\n dummy_model.dummy_int = 1\n dummy_model.save()\n res = api_action.api_dummy(pk=1)\n assert res[\"dummy_int\"] == 1\n\n```\nHere as an example, the real exception and trace will be thrown, make it easy to understand what the issue is:\n\n```python\nimport pytest\nfrom tests.test_server.test_app.views import DummyViewSetFixture\n\n\n@pytest.mark.api_action(view_set_class=DummyViewSetFixture)\ndef test_dummy(db, api_action):\n result = api_action.dummy(pk='bbb')\n assert result['dummy_int'] == 1\n```\n\n```shell\ntests/functionality_tests/test_as_api.py:11 (test_call_as_api)\nself = <django.db.models.fields.BigAutoField: id>, value = 'bb'\n\n def get_prep_value(self, value):\n value = super().get_prep_value(value)\n if value is None:\n return None\n try:\n> return int(value)\nE ValueError: invalid literal for int() with base 10: 'bb'\n\n../venv/lib/python3.9/site-packages/django/db/models/fields/__init__.py:2053: ValueError\n\nThe above exception was the direct cause of the following exception:\n\nqueryset = <QuerySet [<DummyModel: DummyModel object (1)>]>, filter_args = ()\nfilter_kwargs = {'pk': 'bb'}\n\n def get_object_or_404(queryset, *filter_args, **filter_kwargs):\n \"\"\"\n Same as Django's standard shortcut, but make sure to also raise 404\n if the filter_kwargs don't match the required types.\n \"\"\"\n try:\n> return _get_object_or_404(queryset, *filter_args, **filter_kwargs)\n\n../venv/lib/python3.9/site-packages/rest_framework/generics.py:19: \n....\n....\n...\n```\n\nCall endpoints with pagination:\n```python\n@pytest.mark.api_action(view_set_class=DummyAPIViewSet)\ndef test_pagination_data(db, api_action):\n for i in range(1, 3):\n dummy_model = DummyModel()\n dummy_model.dummy_int = 1\n dummy_model.save()\n\n response = api_action.by_dummy_int(dummy_int=1, page=1)\n\n obj = response['results'][0]\n assert obj['dummy_int'] == 1\n\n assert extract_page_number(response['next']) == 2\n\n response = api_action.by_dummy_int(dummy_int=1, page=2)\n assert extract_page_number(response['previous']) == 1\n assert extract_page_number(response['next']) is None\n\n```\n\n\n## Package Testing\n\nThe `drf-api-action` library includes tests to ensure the functionality works as expected. To run the tests run `pytest`:\n\n ```shell\n pytest\n ```\n\nThe tests will be executed, and the results will be displayed in the console.\n\n## Example\n\nExample of using drf-api-action in a [DRF project](https://github.com/Ori-Roza/drf-api-action-example)\n\n## Support & Contribution\n\nFor guidance on support & contribution, see the [contributing guidelines](https://github.com/Ori-Roza/drf-api-action/blob/master/docs/CONTRIBUTING.md).\n\n## Bug Report \n\nFor guidance on how to open a bug, see the [bug report template](https://github.com/Ori-Roza/drf-api-action/blob/master/docs/BUG_REPORT.md).\n\n## Open an Issue\n\nFor guidance on how to open an issue, see the [issue template](https://github.com/Ori-Roza/drf-api-action/blob/master/docs/ISSUE_TEMPLATE.md).\n\n## Code Of Conduct\n\n[code of conduct](https://github.com/Ori-Roza/drf-api-action/blob/master/docs/CODE_OF_CONDUCT.md).\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "drf-api-action elevates DRF testing by simplifying REST endpoint testing to a seamless, function-like experience.",
"version": "1.2.2",
"project_urls": {
"Homepage": "https://github.com/Ori-Roza/drf-api-action",
"Repository": "https://github.com/Ori-Roza/drf-api-action"
},
"split_keywords": [
"pytest",
" mocks",
" testing",
" fixtures",
" tests",
" django"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "e9fdb56f8a6a5de37d7508c09bc67cff6182d6d93664f4e447b4164ee7ec95cb",
"md5": "bf0efc322fb8d4c7cec0ff14f8500d98",
"sha256": "3630ff2bdc537815a522534c94ebbef878e0e738a84c1e8c9640b4e1f79b96ee"
},
"downloads": -1,
"filename": "drf_api_action-1.2.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "bf0efc322fb8d4c7cec0ff14f8500d98",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.7",
"size": 6127,
"upload_time": "2024-05-12T14:20:27",
"upload_time_iso_8601": "2024-05-12T14:20:27.755947Z",
"url": "https://files.pythonhosted.org/packages/e9/fd/b56f8a6a5de37d7508c09bc67cff6182d6d93664f4e447b4164ee7ec95cb/drf_api_action-1.2.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "13485ef3f92d8ccf8ac9b1e0c094466f52744a6cca6f68e76ddd337bf6415355",
"md5": "18f0e687864414f7c21fd0534f5fd631",
"sha256": "c928c935ff40a0a0401232d3e6363db0c505b2e24c11173de7deb3a9be401c65"
},
"downloads": -1,
"filename": "drf_api_action-1.2.2.tar.gz",
"has_sig": false,
"md5_digest": "18f0e687864414f7c21fd0534f5fd631",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.7",
"size": 6581,
"upload_time": "2024-05-12T14:20:29",
"upload_time_iso_8601": "2024-05-12T14:20:29.623897Z",
"url": "https://files.pythonhosted.org/packages/13/48/5ef3f92d8ccf8ac9b1e0c094466f52744a6cca6f68e76ddd337bf6415355/drf_api_action-1.2.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-05-12 14:20:29",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Ori-Roza",
"github_project": "drf-api-action",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "drf-api-action"
}