mirror of
https://github.com/HackSoftware/Django-Styleguide.git
synced 2024-11-29 04:53:46 +03:00
Merge pull request #89 from HackSoftware/improve-testing-sections-a-bit
Improve testing sections a bit
This commit is contained in:
commit
e76d5a8b27
55
README.md
55
README.md
|
@ -60,6 +60,7 @@
|
||||||
- [More ideas](#more-ideas)
|
- [More ideas](#more-ideas)
|
||||||
- [Testing](#testing-2)
|
- [Testing](#testing-2)
|
||||||
- [Naming conventions](#naming-conventions)
|
- [Naming conventions](#naming-conventions)
|
||||||
|
- [Factories](#factories)
|
||||||
- [Celery](#celery)
|
- [Celery](#celery)
|
||||||
- [The basics](#the-basics)
|
- [The basics](#the-basics)
|
||||||
- [Error handling](#error-handling)
|
- [Error handling](#error-handling)
|
||||||
|
@ -799,12 +800,14 @@ When creating the required state for a given test, one can use a combination of:
|
||||||
```python
|
```python
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
from project.payments.selectors import items_get_for_user
|
from project.payments.selectors import items_get_for_user
|
||||||
from project.payments.models import Item, Payment
|
from project.payments.models import Item, Payment
|
||||||
from project.payments.tasks import payment_charge
|
from project.payments.tasks import payment_charge
|
||||||
|
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def item_buy(
|
def item_buy(
|
||||||
*,
|
*,
|
||||||
item: Item,
|
item: Item,
|
||||||
|
@ -813,13 +816,19 @@ def item_buy(
|
||||||
if item in items_get_for_user(user=user):
|
if item in items_get_for_user(user=user):
|
||||||
raise ValidationError(f'Item {item} already in {user} items.')
|
raise ValidationError(f'Item {item} already in {user} items.')
|
||||||
|
|
||||||
payment = Payment.objects.create(
|
payment = Payment(
|
||||||
item=item,
|
item=item,
|
||||||
user=user,
|
user=user,
|
||||||
successful=False
|
successful=False
|
||||||
)
|
)
|
||||||
|
payment.full_clean()
|
||||||
|
payment.save()
|
||||||
|
|
||||||
payment_charge.delay(payment_id=payment.id)
|
# Run the task once the transaction has commited,
|
||||||
|
# guaranteeing the object has been created.
|
||||||
|
transaction.on_commit(
|
||||||
|
lambda: payment_charge.delay(payment_id=payment.id)
|
||||||
|
)
|
||||||
|
|
||||||
return payment
|
return payment
|
||||||
```
|
```
|
||||||
|
@ -844,33 +853,40 @@ from django_styleguide.payments.models import Payment, Item
|
||||||
|
|
||||||
|
|
||||||
class ItemBuyTests(TestCase):
|
class ItemBuyTests(TestCase):
|
||||||
def setUp(self):
|
|
||||||
self.user = User.objects.create_user(username='Test User')
|
|
||||||
self.item = Item.objects.create(
|
|
||||||
name='Test Item',
|
|
||||||
description='Test Item description',
|
|
||||||
price=10.15
|
|
||||||
)
|
|
||||||
|
|
||||||
@patch('project.payments.services.items_get_for_user')
|
@patch('project.payments.services.items_get_for_user')
|
||||||
def test_buying_item_that_is_already_bought_fails(self, items_get_for_user_mock):
|
def test_buying_item_that_is_already_bought_fails(self, items_get_for_user_mock):
|
||||||
"""
|
"""
|
||||||
Since we already have tests for `items_get_for_user`,
|
Since we already have tests for `items_get_for_user`,
|
||||||
we can safely mock it here and give it a proper return value.
|
we can safely mock it here and give it a proper return value.
|
||||||
"""
|
"""
|
||||||
items_get_for_user_mock.return_value = [self.item]
|
user = User(username='Test User')
|
||||||
|
item = Item(
|
||||||
|
name='Test Item',
|
||||||
|
description='Test Item description',
|
||||||
|
price=10.15
|
||||||
|
)
|
||||||
|
|
||||||
|
items_get_for_user_mock.return_value = [item]
|
||||||
|
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
item_buy(user=self.user, item=self.item)
|
item_buy(user=user, item=item)
|
||||||
|
|
||||||
@patch('project.payments.services.payment_charge.delay')
|
@patch('project.payments.services.payment_charge.delay')
|
||||||
def test_buying_item_creates_a_payment_and_calls_charge_task(
|
def test_buying_item_creates_a_payment_and_calls_charge_task(
|
||||||
self,
|
self,
|
||||||
payment_charge_mock
|
payment_charge_mock
|
||||||
):
|
):
|
||||||
|
# How we prepare our tests is a topic for a different discussion
|
||||||
|
user = given_a_user(username="Test user")
|
||||||
|
item = given_a_item(
|
||||||
|
name='Test Item',
|
||||||
|
description='Test Item description',
|
||||||
|
price=10.15
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(0, Payment.objects.count())
|
self.assertEqual(0, Payment.objects.count())
|
||||||
|
|
||||||
payment = item_buy(user=self.user, item=self.item)
|
payment = item_buy(user=user, item=item)
|
||||||
|
|
||||||
self.assertEqual(1, Payment.objects.count())
|
self.assertEqual(1, Payment.objects.count())
|
||||||
self.assertEqual(payment, Payment.objects.first())
|
self.assertEqual(payment, Payment.objects.first())
|
||||||
|
@ -2338,6 +2354,7 @@ project_name
|
||||||
│ ├── __init__.py
|
│ ├── __init__.py
|
||||||
│ └── tests
|
│ └── tests
|
||||||
│ ├── __init__.py
|
│ ├── __init__.py
|
||||||
|
│ ├── factories.py
|
||||||
│ ├── models
|
│ ├── models
|
||||||
│ │ └── __init__.py
|
│ │ └── __init__.py
|
||||||
│ │ └── test_some_model_name.py
|
│ │ └── test_some_model_name.py
|
||||||
|
@ -2388,6 +2405,18 @@ If we are to split the `utils.py` module into submodules, the same will happen f
|
||||||
|
|
||||||
We try to match the structure of our modules with the structure of their respective tests.
|
We try to match the structure of our modules with the structure of their respective tests.
|
||||||
|
|
||||||
|
### Factories
|
||||||
|
|
||||||
|
Factories are a great tool for generating data for your tests.
|
||||||
|
|
||||||
|
When used correctly, you can improve the overall quality of your tests.
|
||||||
|
|
||||||
|
If you are new to this concept, you can refer to the following materials:
|
||||||
|
|
||||||
|
- [Improve your Django tests with fakes and factories](https://www.hacksoft.io/blog/improve-your-tests-django-fakes-and-factories)
|
||||||
|
- [https://www.hacksoft.io/blog/improve-your-tests-django-fakes-and-factories-advanced-usage](https://www.hacksoft.io/blog/improve-your-tests-django-fakes-and-factories-advanced-usage)
|
||||||
|
- [DjangoCon 2022 | factory_boy: testing like a pro](https://www.youtube.com/watch?v=-C-XNHAJF-c)
|
||||||
|
|
||||||
## Celery
|
## Celery
|
||||||
|
|
||||||
We use [Celery](http://www.celeryproject.org/) for the following general cases:
|
We use [Celery](http://www.celeryproject.org/) for the following general cases:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user