[![Latest Version](https://img.shields.io/pypi/v/django_mock_queries.svg)](https://pypi.python.org/pypi/django_mock_queries)
[![Build Status](https://github.com/stphivos/django-mock-queries/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/stphivos/django-mock-queries/actions/workflows/ci.yml)
[![Code Coverage](https://codecov.io/github/stphivos/django-mock-queries/coverage.svg?branch=master)](https://codecov.io/github/stphivos/django-mock-queries?branch=master)
[![Code Climate](https://codeclimate.com/github/stphivos/django-mock-queries/badges/gpa.svg)](https://codeclimate.com/github/stphivos/django-mock-queries)
# Django Mock Queries
A library for mocking Django queryset functions in memory for testing
## Features
* QuerySet style support for method chaining
* Filtering with Q objects
* Aggregates generation
* CRUD functions
* Field lookups
* django-rest-framework serializer asserts
## Examples
```python
from django.db.models import Avg, Q
from django_mock_queries.query import MockSet, MockModel
qs = MockSet(
MockModel(mock_name='john', email='john@gmail.com'),
MockModel(mock_name='jeff', email='jeff@hotmail.com'),
MockModel(mock_name='bill', email='bill@gmail.com'),
)
print([x for x in qs.all().filter(email__icontains='gmail.com').select_related('address')])
# Outputs: [john, bill]
qs = MockSet(
MockModel(mock_name='model s', msrp=70000),
MockModel(mock_name='model x', msrp=80000),
MockModel(mock_name='model 3', msrp=35000),
)
print(qs.all().aggregate(Avg('msrp')))
# Outputs: {'msrp__avg': 61666}
qs = MockSet(
MockModel(mock_name='model x', make='tesla', country='usa'),
MockModel(mock_name='s-class', make='mercedes', country='germany'),
MockModel(mock_name='s90', make='volvo', country='sweden'),
)
print([x for x in qs.all().filter(Q(make__iexact='tesla') | Q(country__iexact='germany'))])
# Outputs: [model x, s-class]
qs = MockSet(cls=MockModel)
print(qs.create(mock_name='my_object', foo='1', bar='a'))
# Outputs: my_object
print([x for x in qs])
# Outputs: [my_object]
```
### Test function that uses Django QuerySet:
```python
from unittest import TestCase
from unittest.mock import patch
from django_mock_queries.query import MockSet, MockModel
class TestApi(TestCase):
"""
Test function applies expected filters by patching Django's user model Manager or Queryset with a MockSet.
"""
users = MockSet()
user_objects = patch('django.contrib.auth.models.User.objects', users)
def active_users(self):
"""
Query active users.
"""
return User.objects.filter(is_active=True).all()
@user_objects
def test_api_active_users_filters_by_is_active_true(self):
self.users.add(
MockModel(mock_name='active user', is_active=True),
MockModel(mock_name='inactive user', is_active=False)
)
for user in self.active_users():
self.assertTrue(user.is_active)
```
### Test django-rest-framework model serializer:
```python
class CarSerializer(serializers.ModelSerializer):
"""
Car model serializer that includes a nested serializer and a method field.
"""
make = ManufacturerSerializer()
speed = serializers.SerializerMethodField()
def get_speed(self, obj):
return obj.format_speed()
class Meta:
model = Car
fields = ('id', 'make', 'model', 'speed',)
def test_car_serializer_fields(self):
"""
Test serializer returns fields with expected values and mock the result of nested serializer for field `make`.
"""
car = Car(id=1, make=Manufacturer(id=1, name='vw'), model='golf', speed=300)
values = {
'id': car.id,
'model': car.model,
'speed': car.formatted_speed(),
}
assert_serializer(CarSerializer) \
.instance(car) \
.returns('id', 'make', 'model', 'speed') \
.values(**values) \
.mocks('make') \
.run()
```
### Full Example
There is a full Django application in the `examples/users` folder. It shows how
to configure `django_mock_queries` in your tests and run them with or without
setting up a Django database. Running the mock tests without a database can be
much faster when your Django application has a lot of database migrations.
To run your Django tests without a database, add a new settings file, and call
`monkey_patch_test_db()`. Use a wildcard import to get all the regular settings
as well.
```python
# settings_mocked.py
from django_mock_queries.mocks import monkey_patch_test_db
from users.settings import *
monkey_patch_test_db()
```
Then run your Django tests with the new settings file:
./manage.py test --settings=users.settings_mocked
Here's the pytest equivalent:
pytest --ds=users.settings_mocked
That will run your tests without setting up a test database. All of your tests
that use Django mock queries should run fine, but what about the tests that
really need a database?
ERROR: test_create (examples.users.analytics.tests.TestApi)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/.../examples/users/analytics/tests.py", line 28, in test_create
start_count = User.objects.count()
[...]
NotSupportedError: Mock database tried to execute SQL for User model.
If you want to run your tests without a database, you need to tell Django
to skip the tests that need a database. You can do that by putting a skip
decorator on the test classes or test methods that need a database.
```python
@skipIfDBFeature('is_mocked')
class TestApi(TestCase):
def test_create(self):
start_count = User.objects.count()
User.objects.create(username='bob')
final_count = User.objects.count()
self.assertEqual(start_count + 1, final_count)
```
## Installation
```bash
pip install django_mock_queries
```
## Contributing
Anything missing or not functioning correctly? PRs are always welcome! Otherwise, you can create an issue so someone else does it when time allows.
You can follow these guidelines:
* Fork the repo from this page
* Clone your fork:
```bash
git clone https://github.com/{your-username}/django-mock-queries.git
cd django-mock-queries
git checkout -b feature/your_cool_feature
```
* Implement feature/fix
* Add/modify relevant tests
* Run tox to verify all tests and flake8 quality checks pass
```bash
tox
```
* Commit and push local branch to your origin
```bash
git commit . -m "New cool feature does this"
git push -u origin HEAD
```
* Create pull request
## TODO
* Add docs as a service like readthedocs with examples for every feature
* Add support for missing QuerySet methods/Field lookups/Aggregation functions:
* Methods that return new QuerySets: `annotate`, `reverse`, `none`, `extra`, `raw`
* Methods that do not return QuerySets: `bulk_create`, `in_bulk`, `as_manager`
* Field lookups: `search`
* Aggregation functions: `StdDev`, `Variance`
Raw data
{
"_id": null,
"home_page": "https://github.com/stphivos/django-mock-queries",
"name": "django-mock-queries",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "django orm mocking unit-testing tdd",
"author": "Phivos Stylianides",
"author_email": "stphivos@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/81/9e/c8cb870abc00d8bc92c719f699ce988c4105501be7c67232af742eeb2085/django_mock_queries-2.3.0.tar.gz",
"platform": null,
"description": "[![Latest Version](https://img.shields.io/pypi/v/django_mock_queries.svg)](https://pypi.python.org/pypi/django_mock_queries)\n[![Build Status](https://github.com/stphivos/django-mock-queries/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/stphivos/django-mock-queries/actions/workflows/ci.yml)\n[![Code Coverage](https://codecov.io/github/stphivos/django-mock-queries/coverage.svg?branch=master)](https://codecov.io/github/stphivos/django-mock-queries?branch=master)\n[![Code Climate](https://codeclimate.com/github/stphivos/django-mock-queries/badges/gpa.svg)](https://codeclimate.com/github/stphivos/django-mock-queries)\n\n# Django Mock Queries\n\nA library for mocking Django queryset functions in memory for testing\n\n## Features\n\n* QuerySet style support for method chaining\n* Filtering with Q objects\n* Aggregates generation\n* CRUD functions\n* Field lookups\n* django-rest-framework serializer asserts\n\n## Examples\n\n```python\nfrom django.db.models import Avg, Q\nfrom django_mock_queries.query import MockSet, MockModel\n\nqs = MockSet(\n MockModel(mock_name='john', email='john@gmail.com'),\n MockModel(mock_name='jeff', email='jeff@hotmail.com'),\n MockModel(mock_name='bill', email='bill@gmail.com'),\n)\n\nprint([x for x in qs.all().filter(email__icontains='gmail.com').select_related('address')])\n# Outputs: [john, bill]\n\nqs = MockSet(\n MockModel(mock_name='model s', msrp=70000),\n MockModel(mock_name='model x', msrp=80000),\n MockModel(mock_name='model 3', msrp=35000),\n)\n\nprint(qs.all().aggregate(Avg('msrp')))\n# Outputs: {'msrp__avg': 61666}\n\nqs = MockSet(\n MockModel(mock_name='model x', make='tesla', country='usa'),\n MockModel(mock_name='s-class', make='mercedes', country='germany'),\n MockModel(mock_name='s90', make='volvo', country='sweden'),\n)\n\nprint([x for x in qs.all().filter(Q(make__iexact='tesla') | Q(country__iexact='germany'))])\n# Outputs: [model x, s-class]\n\nqs = MockSet(cls=MockModel)\nprint(qs.create(mock_name='my_object', foo='1', bar='a'))\n# Outputs: my_object\n\nprint([x for x in qs])\n# Outputs: [my_object]\n```\n\n### Test function that uses Django QuerySet:\n\n```python\nfrom unittest import TestCase\nfrom unittest.mock import patch\nfrom django_mock_queries.query import MockSet, MockModel\n\n\nclass TestApi(TestCase):\n \"\"\"\n Test function applies expected filters by patching Django's user model Manager or Queryset with a MockSet.\n \"\"\"\n users = MockSet()\n user_objects = patch('django.contrib.auth.models.User.objects', users)\n \n def active_users(self):\n \"\"\"\n Query active users.\n \"\"\"\n return User.objects.filter(is_active=True).all()\n\n @user_objects\n def test_api_active_users_filters_by_is_active_true(self):\n self.users.add(\n MockModel(mock_name='active user', is_active=True),\n MockModel(mock_name='inactive user', is_active=False)\n )\n\n for user in self.active_users():\n self.assertTrue(user.is_active)\n```\n\n### Test django-rest-framework model serializer:\n\n```python\nclass CarSerializer(serializers.ModelSerializer):\n \"\"\"\n Car model serializer that includes a nested serializer and a method field.\n \"\"\"\n make = ManufacturerSerializer()\n speed = serializers.SerializerMethodField()\n\n def get_speed(self, obj):\n return obj.format_speed()\n\n class Meta:\n model = Car\n fields = ('id', 'make', 'model', 'speed',)\n\n\ndef test_car_serializer_fields(self):\n \"\"\"\n Test serializer returns fields with expected values and mock the result of nested serializer for field `make`.\n \"\"\"\n car = Car(id=1, make=Manufacturer(id=1, name='vw'), model='golf', speed=300)\n\n values = {\n 'id': car.id,\n 'model': car.model,\n 'speed': car.formatted_speed(),\n }\n\n assert_serializer(CarSerializer) \\\n .instance(car) \\\n .returns('id', 'make', 'model', 'speed') \\\n .values(**values) \\\n .mocks('make') \\\n .run()\n```\n\n### Full Example\n\nThere is a full Django application in the `examples/users` folder. It shows how\nto configure `django_mock_queries` in your tests and run them with or without\nsetting up a Django database. Running the mock tests without a database can be\nmuch faster when your Django application has a lot of database migrations.\n\nTo run your Django tests without a database, add a new settings file, and call\n`monkey_patch_test_db()`. Use a wildcard import to get all the regular settings\nas well.\n\n```python\n# settings_mocked.py\nfrom django_mock_queries.mocks import monkey_patch_test_db\n\nfrom users.settings import *\n\nmonkey_patch_test_db()\n```\n\nThen run your Django tests with the new settings file:\n\n ./manage.py test --settings=users.settings_mocked\n\nHere's the pytest equivalent:\n\n pytest --ds=users.settings_mocked\n\nThat will run your tests without setting up a test database. All of your tests\nthat use Django mock queries should run fine, but what about the tests that\nreally need a database?\n\n ERROR: test_create (examples.users.analytics.tests.TestApi)\n ----------------------------------------------------------------------\n Traceback (most recent call last):\n File \"/.../examples/users/analytics/tests.py\", line 28, in test_create\n start_count = User.objects.count()\n [...]\n NotSupportedError: Mock database tried to execute SQL for User model.\n\nIf you want to run your tests without a database, you need to tell Django\nto skip the tests that need a database. You can do that by putting a skip\ndecorator on the test classes or test methods that need a database.\n\n```python\n@skipIfDBFeature('is_mocked')\nclass TestApi(TestCase):\n def test_create(self):\n start_count = User.objects.count()\n\n User.objects.create(username='bob')\n final_count = User.objects.count()\n\n self.assertEqual(start_count + 1, final_count)\n```\n\n## Installation\n\n```bash\npip install django_mock_queries\n```\n\n## Contributing\n\nAnything missing or not functioning correctly? PRs are always welcome! Otherwise, you can create an issue so someone else does it when time allows.\n\nYou can follow these guidelines:\n\n* Fork the repo from this page\n* Clone your fork:\n```bash\ngit clone https://github.com/{your-username}/django-mock-queries.git\ncd django-mock-queries\ngit checkout -b feature/your_cool_feature\n```\n* Implement feature/fix\n* Add/modify relevant tests\n* Run tox to verify all tests and flake8 quality checks pass\n```bash\ntox\n```\n* Commit and push local branch to your origin\n```bash\ngit commit . -m \"New cool feature does this\"\ngit push -u origin HEAD\n```\n* Create pull request\n\n## TODO\n\n* Add docs as a service like readthedocs with examples for every feature\n* Add support for missing QuerySet methods/Field lookups/Aggregation functions:\n * Methods that return new QuerySets: `annotate`, `reverse`, `none`, `extra`, `raw`\n * Methods that do not return QuerySets: `bulk_create`, `in_bulk`, `as_manager`\n * Field lookups: `search`\n * Aggregation functions: `StdDev`, `Variance`",
"bugtrack_url": null,
"license": "MIT",
"summary": "A django library for mocking queryset functions in memory for testing",
"version": "2.3.0",
"project_urls": {
"Homepage": "https://github.com/stphivos/django-mock-queries"
},
"split_keywords": [
"django",
"orm",
"mocking",
"unit-testing",
"tdd"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "819ec8cb870abc00d8bc92c719f699ce988c4105501be7c67232af742eeb2085",
"md5": "6bf9d12a7522eb09cec7168a056cd54c",
"sha256": "3cc9c3922a1438ea7c318d61269ff9239b696d1d7c2ce4ebfa8cec3d1cf9b970"
},
"downloads": -1,
"filename": "django_mock_queries-2.3.0.tar.gz",
"has_sig": false,
"md5_digest": "6bf9d12a7522eb09cec7168a056cd54c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 20496,
"upload_time": "2024-09-26T15:29:06",
"upload_time_iso_8601": "2024-09-26T15:29:06.816212Z",
"url": "https://files.pythonhosted.org/packages/81/9e/c8cb870abc00d8bc92c719f699ce988c4105501be7c67232af742eeb2085/django_mock_queries-2.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-26 15:29:06",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "stphivos",
"github_project": "django-mock-queries",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "django-mock-queries"
}