38

I'm looking to do some tests and I'm not really familiar with the URLResolver quite yet but I'd like to solve this issue quickly.

In a TestCase, I'd like to add a URL to the resolver so that I can then use Client.get('/url/') and keep it separate from urls.py.

4 Answers 4

55

Since Django 1.8 using of django.test.TestCase.urls is deprecated. You can use django.test.utils.override_settings instead:

from django.test import TestCase from django.test.utils import override_settings urlpatterns = [ # custom urlconf ] @override_settings(ROOT_URLCONF=__name__) class MyTestCase(TestCase): pass 

override_settings can be applied either to a whole class or to a particular method.

Sign up to request clarification or add additional context in comments.

6 Comments

This completely overrides the urlpatterns. What if I want to add to them, instead?
@Joost You can do something like from myapp.urls import urlpatterns as base_patterns and then urlpatterns = base_patterns + [<your custom patterns here>]
I had to add self.reload_urlconf() in my test to force the reload, as well as using @override_settings(ROOT_URLCONF=__name__)
from myapp.urls import urlpatterns as base_patterns didn't work for me because my tests for all other URLs relied on the full paths. I had to do my_project.urls import urlpatterns as base_patterns. Also, because it was my_project.urls, I had to write the full path (e.g. /myapp/path/to/my/view instead of /path/to/my/view) in the tests.
What black magic is going on here with the __name__ parameter? Why do I get a TypeError: unhashable type: 'list' error if urlpatterns is passed in directly instead of specifying __name__?
|
25

https://docs.djangoproject.com/en/2.1/topics/testing/tools/#urlconf-configuration

In your test:

class TestMyViews(TestCase): urls = 'myapp.test_urls' 

This will use myapp/test_urls.py as the ROOT_URLCONF.

1 Comment

To visitors from the future, please note the more appropriate (for modern Django versions) answer @renskiy has added.
7

I know this was asked a while ago, but I thought I'd answer it again to offer something more complete and up-to-date.

You have two options to solve this, one is to provide your own urls file, as suggested by SystemParadox's answer:

class MyTestCase(TestCase): urls = 'my_app.test_urls' 

The other is to monkey patch your urls. This is NOT the recommended way to deal with overriding urls but you might get into a situation where you still need it. To do this for a single test case without affecting the rest you should do it in your setUp() method and then cleanup in your tearDown() method.

import my_app.urls from django.conf.urls import patterns class MyTestCase(TestCase): urls = 'my_app.urls' def setUp(self): super(MyTestCase, self).setUp() self.original_urls = my_app.urls.urlpatterns my_app.urls.urlpatterns += patterns( '', (r'^my/test/url/pattern$', my_view), ) def tearDown(self): super(MyTestCase, self).tearDown() my_app.urls.urlpatterns = self.original_urls 

Please note that this will not work if you omit the urls class attribute. This is because the urls will otherwise be cached and your monkey patching will not take effect if you run your test together with other test cases.

2 Comments

But why would you do this, use monkey-path as a last resort when you cannot properly declare something. Here you explicitly set 'my_app.urls' only to alter it a couple of lines later!
This is certainly not the recommended way to generally override test urls - my_app.urls in this case is the default app urls module, not a test specific one, and it's a hacky way to force urls reload. I just added it because I have encountered a case where monkey patching actually required far effort code than recreating a whole urls module.
1

Couldn't get it running with the answers above. Not even with the override_settings. Found a solution which works for me. My usecase was to write some integration tests where I want to test put/post methods where I needed the urls from my app.

The main clue here is to use the set_urlconf function of django.urls instead of overwriting it in the class or using override_settings.

from django.test import TestCase from django.urls import reverse, set_urlconf class MyTests(TestCase): @classmethod def setUpClass(cls): super().setUpClass() set_urlconf('yourapp.urls') # yourapp is the folder where you define your root urlconf. def test_url_resolving_with_app_urlconf(self): response = self.client.put( path=reverse('namespace:to:your:view-name'), data=test_data ) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.