django-mock-queries


Namedjango-mock-queries JSON
Version 2.3.0 PyPI version JSON
download
home_pagehttps://github.com/stphivos/django-mock-queries
SummaryA django library for mocking queryset functions in memory for testing
upload_time2024-09-26 15:29:06
maintainerNone
docs_urlNone
authorPhivos Stylianides
requires_pythonNone
licenseMIT
keywords django orm mocking unit-testing tdd
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![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"
}
        
Elapsed time: 1.20475s