Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathan Reynolds committed Feb 19, 2011
0 parents commit d9537cc
Show file tree
Hide file tree
Showing 15 changed files with 220 additions and 0 deletions.
20 changes: 20 additions & 0 deletions README.rst
@@ -0,0 +1,20 @@
Mechanize_ support for Django testcases.

Testcases are subclasses of DjangoMechanizeTestCase.

The mechanize browser is accessed via self.browser. Your test will fetch
URLs from a virtual server running your Django project. This defaults to
http://localhost:17681 - use self.browser_url() to avoid hardcoding that
address.

e.g:

::
class MyTestCase(DjangoMechanizeTestCase):
def test_with_mechanize(self):
self.browser.open(self.browser_url('/test_view/'))
self.browser.select_form(name='upload_form')
self.browser.add_file(StringIO('12341234'), 'text/plain', 'test.txt')
self.browser.submit()

.. _Mechanize: http://wwwsearch.sourceforge.net/mechanize/
55 changes: 55 additions & 0 deletions djangomechanize/__init__.py
@@ -0,0 +1,55 @@
from django.core.handlers.wsgi import WSGIHandler
import unittest
import urlparse
import wsgi_intercept, wsgi_intercept.mechanize_intercept


class DjangoMechanizeTestCase(unittest.TestCase):
"""
Mechanize support for Django testcases.
<http://wwwsearch.sourceforge.net/mechanize/>
Testcases are subclasses of DjangoMechanizeTestCase.
The mechanize browser is accessed via self.browser. Your test will fetch
URLs from a virtual server running your Django project. This defaults to
http://localhost:17681 - use self.browser_url() to avoid hardcoding that
address.
e.g:
class MyTestCase(DjangoMechanizeTestCase):
def test_with_mechanize(self):
self.browser.open(self.browser_url('/test_view/'))
self.browser.select_form(name='upload_form')
self.browser.add_file(StringIO('12341234'), 'text/plain', 'test.txt')
self.browser.submit()
"""

TEST_ADDRESS = ('localhost', 17681,)

def setUp(self):
self.browser = self.create_browser()

def browser_url(self, url):
"""
Create a URL for the virtual WSGI server.
e.g browser_url('/'), browser_url(reverse('my_view'))
"""
return urlparse.urljoin('http://%s:%d/' % self.TEST_ADDRESS, url)

def create_browser(self):
"""
Create a Mechanize browser. Intercepts requests to
http://localhost:17681 and sends them to Django's WSGI handler.
This can be overridden via self.TEST_ADDRESS, if your tests need to
use an actual server at this address:port.
Robots.txt is disabled, as it'll likely throw a 404 error in your test.
If you need to test your robots file, use
self.browser.set_handle_robots(True).
"""
host, port = self.TEST_ADDRESS
wsgi_intercept.add_wsgi_intercept(host, port, WSGIHandler)
browser = wsgi_intercept.mechanize_intercept.Browser()
browser.set_handle_robots(False)
return browser
3 changes: 3 additions & 0 deletions requirements.txt
@@ -0,0 +1,3 @@
django
mechanize
wsgi_intercept
24 changes: 24 additions & 0 deletions setup.py
@@ -0,0 +1,24 @@
#!/usr/bin/env python

from setuptools import setup

setup(
name='django-mechanize',
version='0.1',
description='Mechanize support for Django test cases',
long_description=open('README.rst').read(),
author='Nathan Reynolds',
url='http://nreynolds.co.uk/django-mechanize/',
packages=['djangomechanize'],
install_requires=[line.strip() for line in open('requirements.txt')],
test_suite='tests',
zip_safe=True,
classifiers=[
'Development Status :: 4 - Beta',
'Framework :: Django',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Programming Language :: Python',
'Topic :: Software Development :: Testing',
],
)
Empty file added testproject/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions testproject/manage.py
@@ -0,0 +1,11 @@
#!/usr/bin/env python
from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)

if __name__ == "__main__":
execute_manager(settings)
23 changes: 23 additions & 0 deletions testproject/settings.py
@@ -0,0 +1,23 @@
import os.path
import sys

DEBUG = True

SITE_ROOT = os.path.dirname(__file__)

sys.path.insert(0, os.path.join(SITE_ROOT, '..'))

MIDDLEWARE_CLASSES = ()

ROOT_URLCONF = 'urls'

DATABASES = {
'default': {
'ENGINE': 'sqlite3',
'NAME': os.path.join(SITE_ROOT, 'temp', 'testdb.sqlite'),
},
}

INSTALLED_APPS = (
'testapp',
)
Empty file added testproject/testapp/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions testproject/testapp/forms.py
@@ -0,0 +1,6 @@
from django import forms


class TestForm(forms.Form):
upload = forms.FileField()
text = forms.CharField()
Empty file added testproject/testapp/models.py
Empty file.
16 changes: 16 additions & 0 deletions testproject/testapp/templates/testapp/test_view.html
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Test view</title>
</head>
<body>
{% if success %}
Success!
{% else %}
<form method="post" name="upload_form" enctype="multipart/form-data">
{{ form.as_p }}
<p><input type="submit"></p>
</form>
{% endif %}
</body>
</html>
30 changes: 30 additions & 0 deletions testproject/testapp/tests.py
@@ -0,0 +1,30 @@
from djangomechanize import DjangoMechanizeTestCase
from cStringIO import StringIO
import socket


class TestCaseTestCase(DjangoMechanizeTestCase):
def test_upload(self):
# Go to the form and upload a file. The uploaded file must have a
# filename, or Django ignores it.
self.browser.open(self.browser_url('/'))
self.browser.select_form(name='upload_form')
self.browser.add_file(StringIO('12341234'), 'text/plain', 'test.txt')
self.browser.submit()

# Page should contain the message "this field is required", as we
# didn't enter anything for the text field.
assert self.browser.response().read().count('This field is required') == 1

# Enter values for the file field and text field, and submit.
self.browser.select_form(name='upload_form')
self.browser.add_file(StringIO('12341234'), 'text/plain', 'test.txt')
self.browser['text'] = 'text'
self.browser.submit()

# The form should now validate.
assert 'Success!' in self.browser.response().read()

def test_wsgi_intercept(self):
# Check that we're not running a live HTTP server.
self.assertRaises(socket.error, lambda: socket.socket().connect(self.TEST_ADDRESS))
17 changes: 17 additions & 0 deletions testproject/testapp/views.py
@@ -0,0 +1,17 @@
from django.shortcuts import render_to_response
from testapp.forms import TestForm


def test_view(request):
success = None
if request.method == 'POST':
form = TestForm(request.POST, request.FILES)
if form.is_valid():
success = True
else:
form = TestForm()

return render_to_response('testapp/test_view.html', {
'form': form,
'success': success,
})
6 changes: 6 additions & 0 deletions testproject/urls.py
@@ -0,0 +1,6 @@
from django.conf.urls.defaults import *


urlpatterns = patterns('',
('^$', 'testapp.views.test_view'),
)
9 changes: 9 additions & 0 deletions tests.py
@@ -0,0 +1,9 @@
from django.core.management import call_command
import os
import os.path
import sys

os.environ['DJANGO_SETTINGS_MODULE'] = 'testproject.settings'
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'testproject'))

call_command('test')

0 comments on commit d9537cc

Please sign in to comment.