Django Queryset flushing to test a function that accepts a request

I have a utility function in my Django project, it takes a request, gets some data from it and returns the result. I would like to write some tests for this function. Do I need to mock QuerySet at all? I would like to create an object that is not related to the database, and I can provide it with a list of used values ​​(i.e., some fake strings), and then it will act just like a set of queries and allow someone to search for fields on it / filter / get / all, etc.

Does something like this already exist?

+29
source share
9 answers

Not that I knew, but why not use the actual set of queries? The test framework is set up so that you can create sample data in your test and the database is recreated in each test, so there is no reason not to use the real thing.

-7
source

Of course, you can mock QuerySet, you can mock anything.

You can create the object yourself, provide it with the necessary interface and make it return any data that you like. At heart, bullying is nothing but the creation of a β€œtest double” that acts like the real thing for the purpose of your tests.

A low-tech way to get started is to identify an object:

class MockQuerySet(object): pass 

then create one of them and submit it for verification. The test failed, probably with an AttributeError . This will tell you what you need to implement on your MockQuerySet . Repeat until your object is rich enough for your tests.

+17
source

I have the same problem, and it looks like some good person wrote the QuerySets bullying library, it is called mock-django and the specific code you will need is https://github.com/dcramer/mock-django/blob/ master / mock_django / query.py . I think you can just fix your function of object objects to return one of these QuerySetMock objects that you configured to return something expected!

+9
source

For an empty Queryset, I would just select none as Keithhackbarth already said .

However, to simulate a Queryset that will return a list of values, I prefer to use Mock with the model manager spec . As an example (Python 2.7 style - I used the external Mock library ), here is a simple test in which Queryset is filtered and then counted:

 from django.test import TestCase from mock import Mock from .models import Example def queryset_func(queryset, filter_value): """ An example function to be tested """ return queryset.filter(stuff=filter_value).count() class TestQuerysetFunc(TestCase): def test_happy(self): """ 'queryset_func' filters provided queryset and counts result """ m_queryset = Mock(spec=Example.objects) m_queryset.filter.return_value = m_queryset m_queryset.count.return_value = 97 result = func_to_test(m_queryset, '__TEST_VALUE__') self.assertEqual(result, 97) m_queryset.filter.assert_called_once_with(stuff='__TEST_VALUE__') m_queryset.count.assert_called_once_with() 

However, to answer this question, instead of setting return_value for count , it can be easily configured to be a list model instances returned from all .

Note that the chain is processed by setting a filter to return a simulated set of queries:

 m_queryset.filter.return_value = m_queryset 

This must be applied to any query set methods used in the function being tested, for example, exclude , etc.

+6
source

For this, I use the Django.none () function .

For instance:

 class Location(models.Model): name = models.CharField(max_length=100) mock_locations = Location.objects.none() 

This is a method that is often used in Django's own internal tests. Based on comments in code

 Calling none() will create a queryset that never returns any objects and no +query will be executed when accessing the results. A qs.none() queryset +is an instance of ``EmptyQuerySet``. 
+2
source

Try the django_mock_queries library which allows you to mock database access while using some of the features of the Django query set, such as filtering.

Full disclosure: I introduced some features to the project.

0
source

You can mock like this:

 @patch('django.db.models.query.QuerySet') def test_returning_distinct_records_for_city(self, mock_qs): self.assertTrue(mock_qs.called) 
0
source

Have you looked at FactoryBoy? https://factoryboy.readthedocs.io/en/latest/orms.html This is a tool for replacing devices with django orm support - factories basically generate objects like objects (either in memory or in a test database).

Here is a great article to get started: https://www.caktusgroup.com/blog/2013/07/17/factory-boy-alternative-django-testing-fixtures/

0
source

One of the first tips would be to split the function into two parts: one that creates a set of queries and one that manipulates the output. Thus, the verification of the second part is simple.

For a database problem, I investigated if django uses sqlite-in-memory, and I found out that The latest version of django uses the sqlite -in-memory database, from the unittest django page :

When using the SQLite database engine, tests will use in-memory by default (i.e. the database will be created in memory, completely bypassing the file system!).

Biting off a QuerySet will not force you to implement your full logic.

-1
source

Source: https://habr.com/ru/post/1273107/


All Articles