Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Unit test with different settings in Django?

Is there any simple mechanism for overriding Django settings for a unit test? I have a manager on one of my models that returns a specific number of the latest objects. The number of objects it returns is defined by a NUM_LATEST setting.

This has the potential to make my tests fail if someone were to change the setting. How can I override the settings on setUp() and subsequently restore them on tearDown()? If that isn't possible, is there some way I can monkey patch the method or mock the settings?

EDIT: Here is my manager code:

class LatestManager(models.Manager):     """     Returns a specific number of the most recent public Articles as defined by      the NEWS_LATEST_MAX setting.     """     def get_query_set(self):         num_latest = getattr(settings, 'NEWS_NUM_LATEST', 10)         return super(LatestManager, self).get_query_set().filter(is_public=True)[:num_latest] 

The manager uses settings.NEWS_LATEST_MAX to slice the queryset. The getattr() is simply used to provide a default should the setting not exist.

like image 863
Soviut Avatar asked May 27 '09 01:05

Soviut


People also ask

How do you write unit tests in Django?

To write a test you derive from any of the Django (or unittest) test base classes (SimpleTestCase, TransactionTestCase, TestCase, LiveServerTestCase) and then write separate methods to check that specific functionality works as expected (tests use "assert" methods to test that expressions result in True or False values ...

How do I change Django settings?

Default settings These defaults live in the module django/conf/global_settings.py . Here's the algorithm Django uses in compiling settings: Load settings from global_settings.py . Load settings from the specified settings file, overriding the global settings as necessary.

Which is better Pytest or Unittest?

Which is better – pytest or unittest? Although both the frameworks are great for performing testing in python, pytest is easier to work with. The code in pytest is simple, compact, and efficient. For unittest, we will have to import modules, create a class and define the testing functions within that class.


2 Answers

EDIT: This answer applies if you want to change settings for a small number of specific tests.

Since Django 1.4, there are ways to override settings during tests: https://docs.djangoproject.com/en/stable/topics/testing/tools/#overriding-settings

TestCase will have a self.settings context manager, and there will also be an @override_settings decorator that can be applied to either a test method or a whole TestCase subclass.

These features did not exist yet in Django 1.3.

If you want to change settings for all your tests, you'll want to create a separate settings file for test, which can load and override settings from your main settings file. There are several good approaches to this in the other answers; I have seen successful variations on both hspander's and dmitrii's approaches.

like image 134
slinkp Avatar answered Oct 13 '22 12:10

slinkp


You can do anything you like to the UnitTest subclass, including setting and reading instance properties:

from django.conf import settings  class MyTest(unittest.TestCase):    def setUp(self):        self.old_setting = settings.NUM_LATEST        settings.NUM_LATEST = 5 # value tested against in the TestCase     def tearDown(self):        settings.NUM_LATEST = self.old_setting 

Since the django test cases run single-threaded, however, I'm curious about what else may be modifying the NUM_LATEST value? If that "something else" is triggered by your test routine, then I'm not sure any amount of monkey patching will save the test without invalidating the veracity of the tests itself.

like image 25
Jarret Hardie Avatar answered Oct 13 '22 11:10

Jarret Hardie