7

I want to write a unit test that performs HTTP requests directly (instead of using django.test.client.Client).

If you're curious why - it's because I want to test a Thrift-over-HTTP API that I expose from my Django application - and I want to use the Thrift client in the unit test.

The problem is that during tests, the server is not actually being run. When using django.test.client.Client, it will simply call the view functions instead of actually making a HTTP request. (Please correct me if I'm wrong.)

So what would be the best way to force the test framework to start the HTTP server?

I tried writing a bash script that does something like this:

./manage.py testserver --addrport 7000 &
PID=$!
sleep 5
./manage.py test --no-input
kill $PID

But that is messy (and doesn't really work) because 1) I need the sleep (otherwise the test will start before the DB is initialized by the test server) and 2) the test will try to initialize the database again (after the testserver already initialized it).

Any other solutions to this?

Thank you.

ibz
  • 44,461
  • 24
  • 70
  • 86

2 Answers2

7

Yup, you're right - it's a problem and there is a bug for it: http://code.djangoproject.com/ticket/2879

Just, you might then encounter multithreaded problems, intentionally ommited: http://code.djangoproject.com/ticket/10117 http://code.djangoproject.com/ticket/4513 http://code.djangoproject.com/ticket/3357

I am frustrated, thus I wrote a library that includes starting live server in separate thread and cleaning it afterwards: http://devel.almad.net/trac/django-sane-testing/ . It also starts Django's server multithreaded by runtime monkeypatching and you can use cherrypy http instead (which is better anyway).

Only problem is it requires you to use nose as test framework (100% backward compatibility with standard unittest, but if you're already using something else...). You can then just use --with-django and --with-djangoliveserver/--with-cherrypyliveserver. No idea how it will work with thrift.

Just beware:

  • Please do not bug Django devs with bugreports, you're on your own
  • Windmill provides same solution, so if you're using windmill, you'll probably have port conflicts
Almad
  • 5,753
  • 7
  • 35
  • 53
  • Thanks for the nice answer! Sounds like overkill for me though. I guess I'll just go the easy way for now. Which would be: write a normal test (not Django - so it doesn't mess the DB), which connects to the test server, that should be started beforehand. In the test setUp, if connection fails, display a nice message like "please start your Django test server". :) – ibz Jun 18 '09 at 14:48
  • @Almad: [Offtopic] In our slavic languages, pronouns look ok when started with a capital letter. But in English that somehow doesn't fit and breaks the continuity of the sentence. :) – Tomasz Zieliński Aug 23 '11 at 20:10
  • @TomaszZielinski {Offtopic] The pronoun 'I' is always capitalized, When you capitalize any other pronoun away from the start of a sentence, you're referring to a deity or set thereof. – Ion Freeman Aug 03 '16 at 02:30
1

If you want to test your application using real HTTP requests, then use LiveServerTestCase or StaticLiveServerTestCase, which ships with Django.

In your tests.py file, add code like this:

from django.contrib.staticfiles.testing import StaticLiveServerTestCase

class Example(StaticLiveServerTestCase):
    def test_example(self):
        subprocess.check_call(["curl", self.live_server_url])

And then run the tests by running python manage.py test.

Flimm
  • 136,138
  • 45
  • 251
  • 267