mirror of
				https://github.com/HackSoftware/Django-Styleguide.git
				synced 2025-10-31 07:37:25 +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