%global _empty_manifest_terminate_build 0 Name: python-pytest-drf Version: 1.1.3 Release: 1 Summary: A Django REST framework plugin for pytest. License: MIT URL: https://github.com/theY4Kman/pytest-drf Source0: https://mirrors.nju.edu.cn/pypi/web/packages/74/d5/af02389a21bbe799f716da6529c5714c4a000fb2c5ae6e0654ebebc94dca/pytest-drf-1.1.3.tar.gz BuildArch: noarch Requires: python3-djangorestframework Requires: python3-inflection Requires: python3-pytest Requires: python3-pytest-assert-utils Requires: python3-pytest-common-subject Requires: python3-pytest-lambda Requires: python3-typing_extensions %description ``` Yaaaaay! ## Putting it all together ```python # tests/test_kv.py from typing import Any, Dict from pytest_common_subject import precondition_fixture from pytest_drf import ( ViewSetTest, Returns200, Returns201, Returns204, UsesGetMethod, UsesDeleteMethod, UsesDetailEndpoint, UsesListEndpoint, UsesPatchMethod, UsesPostMethod, ) from pytest_drf.util import pluralized, url_for from pytest_lambda import lambda_fixture, static_fixture from pytest_assert_utils import assert_model_attrs def express_key_value(kv: KeyValue) -> Dict[str, Any]: return { 'id': kv.id, 'key': kv.key, 'value': kv.value, } express_key_values = pluralized(express_key_value) class TestKeyValueViewSet(ViewSetTest): list_url = lambda_fixture( lambda: url_for('key-values-list')) detail_url = lambda_fixture( lambda key_value: url_for('key-values-detail', key_value.pk)) class TestList( UsesGetMethod, UsesListEndpoint, Returns200, ): key_values = lambda_fixture( lambda: [ KeyValue.objects.create(key=key, value=value) for key, value in { 'quay': 'worth', 'chi': 'revenue', 'umma': 'gumma', }.items() ], autouse=True, ) def test_it_returns_key_values(self, key_values, results): expected = express_key_values(sorted(key_values, key=lambda kv: kv.id)) actual = results assert expected == actual class TestCreate( UsesPostMethod, UsesListEndpoint, Returns201, ): data = static_fixture({ 'key': 'snakes', 'value': 'hissssssss', }) initial_key_value_ids = precondition_fixture( lambda: set(KeyValue.objects.values_list('id', flat=True))) def test_it_creates_new_key_value(self, initial_key_value_ids, json): expected = initial_key_value_ids | {json['id']} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual def test_it_sets_expected_attrs(self, data, json): key_value = KeyValue.objects.get(pk=json['id']) expected = data assert_model_attrs(key_value, expected) def test_it_returns_key_value(self, json): key_value = KeyValue.objects.get(pk=json['id']) expected = express_key_value(key_value) actual = json assert expected == actual class TestRetrieve( UsesGetMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='monty', value='jython', )) def test_it_returns_key_value(self, key_value, json): expected = express_key_value(key_value) actual = json assert expected == actual class TestUpdate( UsesPatchMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='pipenv', value='was a huge leap forward', )) data = static_fixture({ 'key': 'buuut poetry', 'value': 'locks quicker and i like that', }) def test_it_sets_expected_attrs(self, data, key_value): # We must tell Django to grab fresh data from the database, or we'll # see our stale initial data and think our endpoint is broken! key_value.refresh_from_db() expected = data assert_model_attrs(key_value, expected) def test_it_returns_key_value(self, key_value, json): key_value.refresh_from_db() expected = express_key_value(key_value) actual = json assert expected == actual class TestDestroy( UsesDeleteMethod, UsesDetailEndpoint, Returns204, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='i love', value='YOU', )) initial_key_value_ids = precondition_fixture( lambda key_value: # ensure our to-be-deleted KeyValue exists in our set set(KeyValue.objects.values_list('id', flat=True))) def test_it_deletes_key_value(self, initial_key_value_ids, key_value): expected = initial_key_value_ids - {key_value.id} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual ``` It's quite a feat! Now, we tested an already-existing endpoint here, just for demonstration purposes. But there's a bigger advantage to performing one request per test, and having a single responsibility for each test: we can write the tests first and incrementally build the ViewSet. We run the tests on changes, and when they're all green, we know the endpoint is done. The beauty of the tests-first methodology is that it frees us up to be creative. Because we have a definite end condition, we can experiment with better implementations — more maintainable, easier to read, using best practices, perhaps leaning on a third-party package for heavy lifting. Well, congratulations if you've made it this far. I hope you may find some value in this library, or even from some conventions in these example tests. Good luck out there, and remember: readability counts — in tests, doubly so. ## Bonus: BDD syntax Personally, I like to use `DescribeKeyValueViewSet`, and `DescribeList`, `DescribeCreate`, etc for my test classes. If I'm testing `DescribeCreate` as a particular user, I like to use, e.g., `ContextAsAdmin`. Sometimes `CaseUnauthenticated` hits the spot. And for test methods, I love to omit the `test` in `test_it_does_xyz`, and simply put `it_does_xyz`. To appease my leanings toward BDD namings, I use a `pytest.ini` with these options: ```ini [pytest] # Only search for tests within files matching these patterns python_files = tests.py test_*.py # Discover tests within classes matching these patterns # NOTE: the dash represents a word boundary (functionality provided by pytest-camel-collect) python_classes = Test-* Describe-* Context-* With-* Without-* For-* When-* If-* Case-* # Only methods matching these patterns are considered tests python_functions = test_* it_* its_* ``` About the dashes in `python_classes`: sometimes I'll name a test class `ForAdminUsers`. If I had the pattern `For*`, it would also match a pytest-drf mixin named `ForbidsAnonymousUsers`. [pytest-camel-collect](https://github.com/theY4Kman/pytest-camel-collect) is a little plugin that interprets dashes in `python_classes` as CamelCase word boundaries. However, similar behavior can be had on stock pytest using a pattern like `For[A-Z0-9]*`. Here's what our example `KeyValueViewSet` test would look like with this BDD naming scheme
BDD-esque KeyValueViewSet test ```python from typing import Any, Dict from pytest_common_subject import precondition_fixture from pytest_drf import ( ViewSetTest, Returns200, Returns201, Returns204, UsesGetMethod, UsesDeleteMethod, UsesDetailEndpoint, UsesListEndpoint, UsesPatchMethod, UsesPostMethod, ) from pytest_drf.util import pluralized, url_for from pytest_lambda import lambda_fixture, static_fixture from pytest_assert_utils import assert_model_attrs def express_key_value(kv: KeyValue) -> Dict[str, Any]: return { 'id': kv.id, 'key': kv.key, 'value': kv.value, } express_key_values = pluralized(express_key_value) class DescribeKeyValueViewSet(ViewSetTest): list_url = lambda_fixture( lambda: url_for('key-values-list')) detail_url = lambda_fixture( lambda key_value: url_for('key-values-detail', key_value.pk)) class DescribeList( UsesGetMethod, UsesListEndpoint, Returns200, ): key_values = lambda_fixture( lambda: [ KeyValue.objects.create(key=key, value=value) for key, value in { 'quay': 'worth', 'chi': 'revenue', 'umma': 'gumma', }.items() ], autouse=True, ) def it_returns_key_values(self, key_values, results): expected = express_key_values(sorted(key_values, key=lambda kv: kv.id)) actual = results assert expected == actual class DescribeCreate( UsesPostMethod, UsesListEndpoint, Returns201, ): data = static_fixture({ 'key': 'snakes', 'value': 'hissssssss', }) initial_key_value_ids = precondition_fixture( lambda: set(KeyValue.objects.values_list('id', flat=True))) def it_creates_new_key_value(self, initial_key_value_ids, json): expected = initial_key_value_ids | {json['id']} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual def it_sets_expected_attrs(self, data, json): key_value = KeyValue.objects.get(pk=json['id']) expected = data assert_model_attrs(key_value, expected) def it_returns_key_value(self, json): key_value = KeyValue.objects.get(pk=json['id']) expected = express_key_value(key_value) actual = json assert expected == actual class DescribeRetrieve( UsesGetMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='monty', value='jython', )) def it_returns_key_value(self, key_value, json): expected = express_key_value(key_value) actual = json assert expected == actual class DescribeUpdate( UsesPatchMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='pipenv', value='was a huge leap forward', )) data = static_fixture({ 'key': 'buuut poetry', 'value': 'locks quicker and i like that', }) def it_sets_expected_attrs(self, data, key_value): # We must tell Django to grab fresh data from the database, or we'll # see our stale initial data and think our endpoint is broken! key_value.refresh_from_db() expected = data assert_model_attrs(key_value, expected) def it_returns_key_value(self, key_value, json): key_value.refresh_from_db() expected = express_key_value(key_value) actual = json assert expected == actual class DescribeDestroy( UsesDeleteMethod, UsesDetailEndpoint, Returns204, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='i love', value='YOU', )) initial_key_value_ids = precondition_fixture( lambda key_value: # ensure our to-be-deleted KeyValue exists in our set set(KeyValue.objects.values_list('id', flat=True))) def it_deletes_key_value(self, initial_key_value_ids, key_value): expected = initial_key_value_ids - {key_value.id} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual ```
%package -n python3-pytest-drf Summary: A Django REST framework plugin for pytest. Provides: python-pytest-drf BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: python3-pip %description -n python3-pytest-drf ``` Yaaaaay! ## Putting it all together ```python # tests/test_kv.py from typing import Any, Dict from pytest_common_subject import precondition_fixture from pytest_drf import ( ViewSetTest, Returns200, Returns201, Returns204, UsesGetMethod, UsesDeleteMethod, UsesDetailEndpoint, UsesListEndpoint, UsesPatchMethod, UsesPostMethod, ) from pytest_drf.util import pluralized, url_for from pytest_lambda import lambda_fixture, static_fixture from pytest_assert_utils import assert_model_attrs def express_key_value(kv: KeyValue) -> Dict[str, Any]: return { 'id': kv.id, 'key': kv.key, 'value': kv.value, } express_key_values = pluralized(express_key_value) class TestKeyValueViewSet(ViewSetTest): list_url = lambda_fixture( lambda: url_for('key-values-list')) detail_url = lambda_fixture( lambda key_value: url_for('key-values-detail', key_value.pk)) class TestList( UsesGetMethod, UsesListEndpoint, Returns200, ): key_values = lambda_fixture( lambda: [ KeyValue.objects.create(key=key, value=value) for key, value in { 'quay': 'worth', 'chi': 'revenue', 'umma': 'gumma', }.items() ], autouse=True, ) def test_it_returns_key_values(self, key_values, results): expected = express_key_values(sorted(key_values, key=lambda kv: kv.id)) actual = results assert expected == actual class TestCreate( UsesPostMethod, UsesListEndpoint, Returns201, ): data = static_fixture({ 'key': 'snakes', 'value': 'hissssssss', }) initial_key_value_ids = precondition_fixture( lambda: set(KeyValue.objects.values_list('id', flat=True))) def test_it_creates_new_key_value(self, initial_key_value_ids, json): expected = initial_key_value_ids | {json['id']} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual def test_it_sets_expected_attrs(self, data, json): key_value = KeyValue.objects.get(pk=json['id']) expected = data assert_model_attrs(key_value, expected) def test_it_returns_key_value(self, json): key_value = KeyValue.objects.get(pk=json['id']) expected = express_key_value(key_value) actual = json assert expected == actual class TestRetrieve( UsesGetMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='monty', value='jython', )) def test_it_returns_key_value(self, key_value, json): expected = express_key_value(key_value) actual = json assert expected == actual class TestUpdate( UsesPatchMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='pipenv', value='was a huge leap forward', )) data = static_fixture({ 'key': 'buuut poetry', 'value': 'locks quicker and i like that', }) def test_it_sets_expected_attrs(self, data, key_value): # We must tell Django to grab fresh data from the database, or we'll # see our stale initial data and think our endpoint is broken! key_value.refresh_from_db() expected = data assert_model_attrs(key_value, expected) def test_it_returns_key_value(self, key_value, json): key_value.refresh_from_db() expected = express_key_value(key_value) actual = json assert expected == actual class TestDestroy( UsesDeleteMethod, UsesDetailEndpoint, Returns204, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='i love', value='YOU', )) initial_key_value_ids = precondition_fixture( lambda key_value: # ensure our to-be-deleted KeyValue exists in our set set(KeyValue.objects.values_list('id', flat=True))) def test_it_deletes_key_value(self, initial_key_value_ids, key_value): expected = initial_key_value_ids - {key_value.id} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual ``` It's quite a feat! Now, we tested an already-existing endpoint here, just for demonstration purposes. But there's a bigger advantage to performing one request per test, and having a single responsibility for each test: we can write the tests first and incrementally build the ViewSet. We run the tests on changes, and when they're all green, we know the endpoint is done. The beauty of the tests-first methodology is that it frees us up to be creative. Because we have a definite end condition, we can experiment with better implementations — more maintainable, easier to read, using best practices, perhaps leaning on a third-party package for heavy lifting. Well, congratulations if you've made it this far. I hope you may find some value in this library, or even from some conventions in these example tests. Good luck out there, and remember: readability counts — in tests, doubly so. ## Bonus: BDD syntax Personally, I like to use `DescribeKeyValueViewSet`, and `DescribeList`, `DescribeCreate`, etc for my test classes. If I'm testing `DescribeCreate` as a particular user, I like to use, e.g., `ContextAsAdmin`. Sometimes `CaseUnauthenticated` hits the spot. And for test methods, I love to omit the `test` in `test_it_does_xyz`, and simply put `it_does_xyz`. To appease my leanings toward BDD namings, I use a `pytest.ini` with these options: ```ini [pytest] # Only search for tests within files matching these patterns python_files = tests.py test_*.py # Discover tests within classes matching these patterns # NOTE: the dash represents a word boundary (functionality provided by pytest-camel-collect) python_classes = Test-* Describe-* Context-* With-* Without-* For-* When-* If-* Case-* # Only methods matching these patterns are considered tests python_functions = test_* it_* its_* ``` About the dashes in `python_classes`: sometimes I'll name a test class `ForAdminUsers`. If I had the pattern `For*`, it would also match a pytest-drf mixin named `ForbidsAnonymousUsers`. [pytest-camel-collect](https://github.com/theY4Kman/pytest-camel-collect) is a little plugin that interprets dashes in `python_classes` as CamelCase word boundaries. However, similar behavior can be had on stock pytest using a pattern like `For[A-Z0-9]*`. Here's what our example `KeyValueViewSet` test would look like with this BDD naming scheme
BDD-esque KeyValueViewSet test ```python from typing import Any, Dict from pytest_common_subject import precondition_fixture from pytest_drf import ( ViewSetTest, Returns200, Returns201, Returns204, UsesGetMethod, UsesDeleteMethod, UsesDetailEndpoint, UsesListEndpoint, UsesPatchMethod, UsesPostMethod, ) from pytest_drf.util import pluralized, url_for from pytest_lambda import lambda_fixture, static_fixture from pytest_assert_utils import assert_model_attrs def express_key_value(kv: KeyValue) -> Dict[str, Any]: return { 'id': kv.id, 'key': kv.key, 'value': kv.value, } express_key_values = pluralized(express_key_value) class DescribeKeyValueViewSet(ViewSetTest): list_url = lambda_fixture( lambda: url_for('key-values-list')) detail_url = lambda_fixture( lambda key_value: url_for('key-values-detail', key_value.pk)) class DescribeList( UsesGetMethod, UsesListEndpoint, Returns200, ): key_values = lambda_fixture( lambda: [ KeyValue.objects.create(key=key, value=value) for key, value in { 'quay': 'worth', 'chi': 'revenue', 'umma': 'gumma', }.items() ], autouse=True, ) def it_returns_key_values(self, key_values, results): expected = express_key_values(sorted(key_values, key=lambda kv: kv.id)) actual = results assert expected == actual class DescribeCreate( UsesPostMethod, UsesListEndpoint, Returns201, ): data = static_fixture({ 'key': 'snakes', 'value': 'hissssssss', }) initial_key_value_ids = precondition_fixture( lambda: set(KeyValue.objects.values_list('id', flat=True))) def it_creates_new_key_value(self, initial_key_value_ids, json): expected = initial_key_value_ids | {json['id']} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual def it_sets_expected_attrs(self, data, json): key_value = KeyValue.objects.get(pk=json['id']) expected = data assert_model_attrs(key_value, expected) def it_returns_key_value(self, json): key_value = KeyValue.objects.get(pk=json['id']) expected = express_key_value(key_value) actual = json assert expected == actual class DescribeRetrieve( UsesGetMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='monty', value='jython', )) def it_returns_key_value(self, key_value, json): expected = express_key_value(key_value) actual = json assert expected == actual class DescribeUpdate( UsesPatchMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='pipenv', value='was a huge leap forward', )) data = static_fixture({ 'key': 'buuut poetry', 'value': 'locks quicker and i like that', }) def it_sets_expected_attrs(self, data, key_value): # We must tell Django to grab fresh data from the database, or we'll # see our stale initial data and think our endpoint is broken! key_value.refresh_from_db() expected = data assert_model_attrs(key_value, expected) def it_returns_key_value(self, key_value, json): key_value.refresh_from_db() expected = express_key_value(key_value) actual = json assert expected == actual class DescribeDestroy( UsesDeleteMethod, UsesDetailEndpoint, Returns204, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='i love', value='YOU', )) initial_key_value_ids = precondition_fixture( lambda key_value: # ensure our to-be-deleted KeyValue exists in our set set(KeyValue.objects.values_list('id', flat=True))) def it_deletes_key_value(self, initial_key_value_ids, key_value): expected = initial_key_value_ids - {key_value.id} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual ```
%package help Summary: Development documents and examples for pytest-drf Provides: python3-pytest-drf-doc %description help ``` Yaaaaay! ## Putting it all together ```python # tests/test_kv.py from typing import Any, Dict from pytest_common_subject import precondition_fixture from pytest_drf import ( ViewSetTest, Returns200, Returns201, Returns204, UsesGetMethod, UsesDeleteMethod, UsesDetailEndpoint, UsesListEndpoint, UsesPatchMethod, UsesPostMethod, ) from pytest_drf.util import pluralized, url_for from pytest_lambda import lambda_fixture, static_fixture from pytest_assert_utils import assert_model_attrs def express_key_value(kv: KeyValue) -> Dict[str, Any]: return { 'id': kv.id, 'key': kv.key, 'value': kv.value, } express_key_values = pluralized(express_key_value) class TestKeyValueViewSet(ViewSetTest): list_url = lambda_fixture( lambda: url_for('key-values-list')) detail_url = lambda_fixture( lambda key_value: url_for('key-values-detail', key_value.pk)) class TestList( UsesGetMethod, UsesListEndpoint, Returns200, ): key_values = lambda_fixture( lambda: [ KeyValue.objects.create(key=key, value=value) for key, value in { 'quay': 'worth', 'chi': 'revenue', 'umma': 'gumma', }.items() ], autouse=True, ) def test_it_returns_key_values(self, key_values, results): expected = express_key_values(sorted(key_values, key=lambda kv: kv.id)) actual = results assert expected == actual class TestCreate( UsesPostMethod, UsesListEndpoint, Returns201, ): data = static_fixture({ 'key': 'snakes', 'value': 'hissssssss', }) initial_key_value_ids = precondition_fixture( lambda: set(KeyValue.objects.values_list('id', flat=True))) def test_it_creates_new_key_value(self, initial_key_value_ids, json): expected = initial_key_value_ids | {json['id']} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual def test_it_sets_expected_attrs(self, data, json): key_value = KeyValue.objects.get(pk=json['id']) expected = data assert_model_attrs(key_value, expected) def test_it_returns_key_value(self, json): key_value = KeyValue.objects.get(pk=json['id']) expected = express_key_value(key_value) actual = json assert expected == actual class TestRetrieve( UsesGetMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='monty', value='jython', )) def test_it_returns_key_value(self, key_value, json): expected = express_key_value(key_value) actual = json assert expected == actual class TestUpdate( UsesPatchMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='pipenv', value='was a huge leap forward', )) data = static_fixture({ 'key': 'buuut poetry', 'value': 'locks quicker and i like that', }) def test_it_sets_expected_attrs(self, data, key_value): # We must tell Django to grab fresh data from the database, or we'll # see our stale initial data and think our endpoint is broken! key_value.refresh_from_db() expected = data assert_model_attrs(key_value, expected) def test_it_returns_key_value(self, key_value, json): key_value.refresh_from_db() expected = express_key_value(key_value) actual = json assert expected == actual class TestDestroy( UsesDeleteMethod, UsesDetailEndpoint, Returns204, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='i love', value='YOU', )) initial_key_value_ids = precondition_fixture( lambda key_value: # ensure our to-be-deleted KeyValue exists in our set set(KeyValue.objects.values_list('id', flat=True))) def test_it_deletes_key_value(self, initial_key_value_ids, key_value): expected = initial_key_value_ids - {key_value.id} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual ``` It's quite a feat! Now, we tested an already-existing endpoint here, just for demonstration purposes. But there's a bigger advantage to performing one request per test, and having a single responsibility for each test: we can write the tests first and incrementally build the ViewSet. We run the tests on changes, and when they're all green, we know the endpoint is done. The beauty of the tests-first methodology is that it frees us up to be creative. Because we have a definite end condition, we can experiment with better implementations — more maintainable, easier to read, using best practices, perhaps leaning on a third-party package for heavy lifting. Well, congratulations if you've made it this far. I hope you may find some value in this library, or even from some conventions in these example tests. Good luck out there, and remember: readability counts — in tests, doubly so. ## Bonus: BDD syntax Personally, I like to use `DescribeKeyValueViewSet`, and `DescribeList`, `DescribeCreate`, etc for my test classes. If I'm testing `DescribeCreate` as a particular user, I like to use, e.g., `ContextAsAdmin`. Sometimes `CaseUnauthenticated` hits the spot. And for test methods, I love to omit the `test` in `test_it_does_xyz`, and simply put `it_does_xyz`. To appease my leanings toward BDD namings, I use a `pytest.ini` with these options: ```ini [pytest] # Only search for tests within files matching these patterns python_files = tests.py test_*.py # Discover tests within classes matching these patterns # NOTE: the dash represents a word boundary (functionality provided by pytest-camel-collect) python_classes = Test-* Describe-* Context-* With-* Without-* For-* When-* If-* Case-* # Only methods matching these patterns are considered tests python_functions = test_* it_* its_* ``` About the dashes in `python_classes`: sometimes I'll name a test class `ForAdminUsers`. If I had the pattern `For*`, it would also match a pytest-drf mixin named `ForbidsAnonymousUsers`. [pytest-camel-collect](https://github.com/theY4Kman/pytest-camel-collect) is a little plugin that interprets dashes in `python_classes` as CamelCase word boundaries. However, similar behavior can be had on stock pytest using a pattern like `For[A-Z0-9]*`. Here's what our example `KeyValueViewSet` test would look like with this BDD naming scheme
BDD-esque KeyValueViewSet test ```python from typing import Any, Dict from pytest_common_subject import precondition_fixture from pytest_drf import ( ViewSetTest, Returns200, Returns201, Returns204, UsesGetMethod, UsesDeleteMethod, UsesDetailEndpoint, UsesListEndpoint, UsesPatchMethod, UsesPostMethod, ) from pytest_drf.util import pluralized, url_for from pytest_lambda import lambda_fixture, static_fixture from pytest_assert_utils import assert_model_attrs def express_key_value(kv: KeyValue) -> Dict[str, Any]: return { 'id': kv.id, 'key': kv.key, 'value': kv.value, } express_key_values = pluralized(express_key_value) class DescribeKeyValueViewSet(ViewSetTest): list_url = lambda_fixture( lambda: url_for('key-values-list')) detail_url = lambda_fixture( lambda key_value: url_for('key-values-detail', key_value.pk)) class DescribeList( UsesGetMethod, UsesListEndpoint, Returns200, ): key_values = lambda_fixture( lambda: [ KeyValue.objects.create(key=key, value=value) for key, value in { 'quay': 'worth', 'chi': 'revenue', 'umma': 'gumma', }.items() ], autouse=True, ) def it_returns_key_values(self, key_values, results): expected = express_key_values(sorted(key_values, key=lambda kv: kv.id)) actual = results assert expected == actual class DescribeCreate( UsesPostMethod, UsesListEndpoint, Returns201, ): data = static_fixture({ 'key': 'snakes', 'value': 'hissssssss', }) initial_key_value_ids = precondition_fixture( lambda: set(KeyValue.objects.values_list('id', flat=True))) def it_creates_new_key_value(self, initial_key_value_ids, json): expected = initial_key_value_ids | {json['id']} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual def it_sets_expected_attrs(self, data, json): key_value = KeyValue.objects.get(pk=json['id']) expected = data assert_model_attrs(key_value, expected) def it_returns_key_value(self, json): key_value = KeyValue.objects.get(pk=json['id']) expected = express_key_value(key_value) actual = json assert expected == actual class DescribeRetrieve( UsesGetMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='monty', value='jython', )) def it_returns_key_value(self, key_value, json): expected = express_key_value(key_value) actual = json assert expected == actual class DescribeUpdate( UsesPatchMethod, UsesDetailEndpoint, Returns200, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='pipenv', value='was a huge leap forward', )) data = static_fixture({ 'key': 'buuut poetry', 'value': 'locks quicker and i like that', }) def it_sets_expected_attrs(self, data, key_value): # We must tell Django to grab fresh data from the database, or we'll # see our stale initial data and think our endpoint is broken! key_value.refresh_from_db() expected = data assert_model_attrs(key_value, expected) def it_returns_key_value(self, key_value, json): key_value.refresh_from_db() expected = express_key_value(key_value) actual = json assert expected == actual class DescribeDestroy( UsesDeleteMethod, UsesDetailEndpoint, Returns204, ): key_value = lambda_fixture( lambda: KeyValue.objects.create( key='i love', value='YOU', )) initial_key_value_ids = precondition_fixture( lambda key_value: # ensure our to-be-deleted KeyValue exists in our set set(KeyValue.objects.values_list('id', flat=True))) def it_deletes_key_value(self, initial_key_value_ids, key_value): expected = initial_key_value_ids - {key_value.id} actual = set(KeyValue.objects.values_list('id', flat=True)) assert expected == actual ```
%prep %autosetup -n pytest-drf-1.1.3 %build %py3_build %install %py3_install install -d -m755 %{buildroot}/%{_pkgdocdir} if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi pushd %{buildroot} if [ -d usr/lib ]; then find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/lib64 ]; then find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/bin ]; then find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/sbin ]; then find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst fi touch doclist.lst if [ -d usr/share/man ]; then find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst fi popd mv %{buildroot}/filelist.lst . mv %{buildroot}/doclist.lst . %files -n python3-pytest-drf -f filelist.lst %dir %{python3_sitelib}/* %files help -f doclist.lst %{_docdir}/* %changelog * Fri May 05 2023 Python_Bot - 1.1.3-1 - Package Spec generated