Merge pull request #13 from rafaelcaricio/django-1.8-support
Django 1.8 support / Project revamp
This commit is contained in:
commit
4b2926615c
46 changed files with 442 additions and 1224 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,3 +10,4 @@ dist/
|
|||
.project
|
||||
.pydevproject
|
||||
build/
|
||||
*.sqlite3
|
||||
|
|
16
Makefile
16
Makefile
|
@ -3,11 +3,17 @@ setup: deps db
|
|||
deps:
|
||||
@pip install -r requirements.txt
|
||||
|
||||
pyvows: db
|
||||
@env PYTHONPATH=$$PYTHONPATH:vows/sandbox/:. pyvows -c -l django_pyvows --profile-threshold 95 vows/
|
||||
sandbox_run:
|
||||
@env PYTHONPATH=sandbox:.:$$PYTHONPATH python sandbox/manage.py runserver
|
||||
|
||||
ci_test:
|
||||
@env PYTHONPATH=$$PYTHONPATH:vows/sandbox/:. python vows/sandbox/manage.py syncdb && pyvows --no_color --cover --cover_package=django_pyvows --cover_threshold=100 -r django_pyvows.coverage.xml -x vows/
|
||||
sandbox_shell:
|
||||
@env PYTHONPATH=sandbox:.:$$PYTHONPATH python sandbox/manage.py shell
|
||||
|
||||
pyvows:
|
||||
@env PYTHONPATH=sandbox:.:$$PYTHONPATH pyvows -c -l django_pyvows --profile-threshold 95 vows/
|
||||
|
||||
ci_test: db
|
||||
@env PYTHONPATH=sandbox:.:$$PYTHONPATH pyvows -c -l django_pyvows --profile-threshold 95 -r django_pyvows.coverage.xml vows/
|
||||
|
||||
db:
|
||||
@env PYTHONPATH=$$PYTHONPATH:. python vows/sandbox/manage.py syncdb
|
||||
@env PYTHONPATH=$$PYTHONPATH:. python sandbox/manage.py syncdb --noinput
|
||||
|
|
64
README.md
64
README.md
|
@ -1,58 +1,52 @@
|
|||
Django-Pyvows
|
||||
=============
|
||||
# Django-PyVows
|
||||
|
||||
This project is an extension of pyVows to test [Django](https://www.djangoproject.com/) projects. It enables usage of core Django testing tools in a way that is in sync with pyVows workflow mindset.
|
||||
|
||||
Pyvows
|
||||
-------
|
||||
PyVows is a BDD (Behaviour Driven Development) inspired by Vows for node.js
|
||||
|
||||
pyvows is a BDD (Behaviour Driven Development) inspired by Vows for node.js
|
||||
More documentation about pyVows can be found at [the project homepage](http://pyvows.org) or for more updated usage check the project [tests itself](https://github.com/heynemann/pyvows/tree/master/tests).
|
||||
|
||||
More documentation about pyvows can be found at the project homepage
|
||||
Django-PyVows is in sync with the latest Django developments and supports Django 1.8.
|
||||
|
||||
http://pyvows.org
|
||||
## Usage
|
||||
|
||||
Django-Pyvows
|
||||
--------------
|
||||
|
||||
This project contains extensions to test Django projects under pyVows.
|
||||
|
||||
Using Django-Pyvows
|
||||
-------------------
|
||||
|
||||
There is no need to modify your project to use Django-PyVows. You only have to create the vows
|
||||
as you usually would, start the server and call your project urls:
|
||||
There is no need to modify your project to use Django-PyVows. You only have to define where is your project settings module and start calling your project urls in your tests.
|
||||
|
||||
```python
|
||||
from pyvows import Vows, expect
|
||||
|
||||
from django_pyvows.context import DjangoHTTPContext
|
||||
from django_pyvows.context import DjangoContext
|
||||
|
||||
@Vows.batch
|
||||
class ContextTest(DjangoHTTPContext):
|
||||
class SimpleTestVows(DjangoContext):
|
||||
|
||||
def setup(self):
|
||||
self.start_server()
|
||||
def settings_module(self):
|
||||
return 'yourproject.settings'
|
||||
|
||||
def topic(self):
|
||||
return self.get('/mygreaturl/')
|
||||
|
||||
def should_be_a_success(self, topic):
|
||||
expect(topic.getcode()).to_equal(200)
|
||||
expect(topic.status_code).to_equal(200)
|
||||
|
||||
def should_return_the_correct_response_type(self, topic):
|
||||
expect(topic.headers.type).to_equal("text/html")
|
||||
def should_return_the_correct_response(self, topic):
|
||||
expect(topic).contains("Welcome!")
|
||||
```
|
||||
|
||||
To work you only need to override the `get_settings` method from DjangoHTTPContext to
|
||||
return the path of your settings module. The default `get_settings` returns `"settings"`.
|
||||
The default `settings_module` is `settings` so you should define it accordly based on your `PYTHONPATH`.
|
||||
|
||||
More info: https://github.com/rafaelcaricio/django-pyvows/wiki
|
||||
### HTTP Client
|
||||
|
||||
External links
|
||||
--------------
|
||||
- Asynchronous Testing with Django and PyVows
|
||||
- http://www.realpython.com/blog/python/asynchronous-testing-with-django-and-pyvows/
|
||||
- Unit Testing with pyVows and Django
|
||||
- http://www.realpython.com/blog/python/unit-testing-with-pyvows-and-django/
|
||||
- Integration testing with pyVows and Django
|
||||
- http://www.realpython.com/blog/python/integration-testing-with-pyvows-and-django/
|
||||
We support `django.test.Client`, the methods `DjangoContext.get` and `DjangoContext.post` are actually simple wrappers around it so [the usage](https://docs.djangoproject.com/en/1.8/topics/testing/tools/#the-test-client) is the same. The test client is also available in the `DjangoContext` instance as `self.client`.
|
||||
|
||||
### Assertions
|
||||
|
||||
The available assertions in Django-PyVows are the same as in `django.test.SimpleTestCase` they were adapted to the context of BDD and PyVows.
|
||||
|
||||
- `contains`: reflects the `django.test.SimpleTestCase.assertContains`. Check usage at: [https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertContains](https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertContains)
|
||||
- `redirects_to`: reflects the `django.test.SimpleTestCase.assertRedirects`. Check usage at: [https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertRedirects](https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertRedirects)
|
||||
- `with_form_error`: reflects the `django.test.SimpleTestCase.assertFormError`. Check usage at: [https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertFormError](https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertFormError)
|
||||
|
||||
### Settings Override
|
||||
|
||||
TODO
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
|
@ -8,4 +7,5 @@
|
|||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from context import DjangoContext, DjangoHTTPContext
|
||||
from context import DjangoContext # NOQA
|
||||
from assertions import * # NOQA
|
||||
|
|
33
django_pyvows/assertions.py
Normal file
33
django_pyvows/assertions.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from django.test import SimpleTestCase
|
||||
from pyvows import Vows
|
||||
|
||||
|
||||
class _Dummy(SimpleTestCase):
|
||||
def nop():
|
||||
pass
|
||||
|
||||
dummy_testcase = _Dummy('nop')
|
||||
|
||||
|
||||
@Vows.assertion
|
||||
def redirects_to(*args, **kwargs):
|
||||
return dummy_testcase.assertRedirects(*args, **kwargs)
|
||||
|
||||
|
||||
@Vows.assertion
|
||||
def contains(*args, **kwargs):
|
||||
return dummy_testcase.assertContains(*args, **kwargs)
|
||||
|
||||
|
||||
@Vows.assertion
|
||||
def with_form_error(*args, **kwargs):
|
||||
return dummy_testcase.assertFormError(*args, **kwargs)
|
|
@ -1,13 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from urls import *
|
||||
from models import *
|
||||
from templates import *
|
|
@ -1,119 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from pyvows import Vows
|
||||
|
||||
class Model(object):
|
||||
def __init__(self, context, model):
|
||||
from django.db import models
|
||||
|
||||
self.context = context
|
||||
if isinstance(model, models.Model):
|
||||
model = model.__class__
|
||||
self.model = model
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.model(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def admin(self):
|
||||
from django.contrib import admin
|
||||
if self.model not in admin.site._registry:
|
||||
raise admin.sites.NotRegistered('The model %s is not registered' % self.model.__name__)
|
||||
return admin.site._registry[self.model]
|
||||
|
||||
@Vows.assertion
|
||||
def to_be_in_admin(topic):
|
||||
from django.contrib import admin
|
||||
try:
|
||||
assert topic.admin
|
||||
except admin.sites.NotRegistered:
|
||||
assert False, "The model %s isn't registered in admin." % topic.model.__name__
|
||||
|
||||
@Vows.assertion
|
||||
def to_have_field(topic, field_name, field_class=None, **kwargs):
|
||||
from django.db import models
|
||||
|
||||
if isinstance(topic, Model):
|
||||
topic = topic.model
|
||||
|
||||
if isinstance(topic, models.Model):
|
||||
topic = topic.__class__
|
||||
|
||||
if not field_class:
|
||||
field_class = models.Field
|
||||
|
||||
field = topic._meta.get_field(field_name)
|
||||
assert isinstance(field, field_class), "The '%s.%s' is not an instance of '%s'" % (topic.__name__, field_name, field_class.__name__)
|
||||
if kwargs:
|
||||
for attr, value in kwargs.items():
|
||||
field_value = getattr(field, attr)
|
||||
assert field_value == value, "The field option '%s' should be equal to '%s', but it's equal to '%s'" % (attr, value, field_value)
|
||||
|
||||
@Vows.assertion
|
||||
def to_be_cruddable(topic, defaults={}):
|
||||
import django.db.models.fields as fields
|
||||
instance = __create_or_update_instance(topic, None, defaults)
|
||||
|
||||
assert instance, "An instance could not be created for model %s" % topic.model.__name__
|
||||
|
||||
retrieved = topic.model.objects.get(id=instance.id)
|
||||
assert retrieved.id == instance.id, "An instance could not be retrieved for model %s with id %d" % (topic.model.__name__, instance.id)
|
||||
|
||||
for key, value in defaults.iteritems():
|
||||
assert value == getattr(retrieved, key), "The default specified value of '%s' should have been set in the '%s' property of the instance but it was not" % (value, key)
|
||||
|
||||
updated = __create_or_update_instance(topic, retrieved, defaults)
|
||||
|
||||
for field, value in topic.model._meta._field_cache:
|
||||
if field.__class__ == fields.AutoField:
|
||||
continue
|
||||
|
||||
if field.name in defaults:
|
||||
continue
|
||||
|
||||
assert getattr(updated, field.name) != getattr(instance, field.name), "The instance should have been updated but the field %s is the same in both the original instance and the updated one (%s)." % (field.name, getattr(updated, field.name))
|
||||
|
||||
instance.delete()
|
||||
object_count = topic.model.objects.count()
|
||||
assert object_count == 0, "Object should have been deleted, but it wasn't (count: %d)" % object_count
|
||||
|
||||
def __create_or_update_instance(topic, instance, defaults):
|
||||
import django.db.models.fields as fields
|
||||
arguments = {}
|
||||
for field, value in topic.model._meta._field_cache:
|
||||
if field.__class__ == fields.AutoField:
|
||||
continue
|
||||
|
||||
if field.name in defaults:
|
||||
arguments[field.name] = defaults[field.name]
|
||||
continue
|
||||
|
||||
if field.__class__ == fields.CharField:
|
||||
__add_char_value_for(field, instance, arguments)
|
||||
|
||||
if instance:
|
||||
for key, value in arguments.iteritems():
|
||||
setattr(instance, key, value)
|
||||
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
return topic.model.objects.create(**arguments)
|
||||
|
||||
def __add_char_value_for(field, instance, arguments):
|
||||
value = "monty python"
|
||||
if instance:
|
||||
value = getattr(instance, field.name) + '2'
|
||||
if field.max_length:
|
||||
if instance:
|
||||
value = value[:len(value) - 2] + '2'
|
||||
value = (value * field.max_length)[:field.max_length]
|
||||
arguments[field.name] = value
|
|
@ -1,57 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from lxml.etree import fromstring
|
||||
from lxml.cssselect import CSSSelector
|
||||
|
||||
from pyvows import Vows, expect
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
|
||||
class Template(object):
|
||||
def __init__(self, template_name, context):
|
||||
self.template_name = template_name
|
||||
self.context = context
|
||||
self.doc = None
|
||||
|
||||
def load(self):
|
||||
if self.doc is None:
|
||||
self.doc = fromstring(render_to_string(self.template_name, self.context))
|
||||
return self.doc
|
||||
|
||||
def select_element(self, selector):
|
||||
sel = CSSSelector(selector)
|
||||
return sel(self.load())
|
||||
|
||||
def _to_contain(self, selector):
|
||||
return len(self.select_element(selector)) > 0
|
||||
|
||||
def get_text(self, selector):
|
||||
return "".join((c.text for c in self.select_element(selector)))
|
||||
|
||||
def __unicode__(self):
|
||||
return self.template_name
|
||||
|
||||
@Vows.assertion
|
||||
def to_have_contents_of(topic, expected):
|
||||
expect(topic.content).to_be_like(expected)
|
||||
|
||||
@Vows.assertion
|
||||
def to_contain(topic, selector):
|
||||
assert isinstance(topic, Template), "Only django_pyvows.Template items can be verified for mapping"
|
||||
assert topic._to_contain(selector), "Expected template(%s) to have an element(%s), but it don't have" % \
|
||||
(unicode(topic), selector)
|
||||
|
||||
@Vows.assertion
|
||||
def not_to_contain(topic, selector):
|
||||
assert isinstance(topic, Template), "Only django_pyvows.Template items can be verified for mapping"
|
||||
assert not topic._to_contain(selector), "Expected template(%s) to not have an element(%s), but it have" % \
|
||||
(unicode(topic), selector)
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from pyvows import Vows, expect
|
||||
from django.http import HttpResponse
|
||||
|
||||
|
||||
class Url(object):
|
||||
def __init__(self, context, path):
|
||||
self.context = context
|
||||
self.path = path
|
||||
|
||||
@Vows.assertion
|
||||
def to_be_mapped(topic):
|
||||
verify_url_is_mapped_to_method(topic)
|
||||
|
||||
@Vows.assertion
|
||||
def to_match_view(topic, view):
|
||||
verify_url_is_mapped_to_method(topic, view, True)
|
||||
|
||||
@Vows.assertion
|
||||
def to_be_http_response(topic):
|
||||
expect(topic).to_be_instance_of(HttpResponse)
|
||||
|
||||
def verify_url_is_mapped_to_method(topic, method=None, assert_method_as_well=False):
|
||||
assert isinstance(topic, Url), "Only django_pyvows.Url items can be verified for mapping"
|
||||
|
||||
from django.conf import settings
|
||||
project_urls = settings.ROOT_URLCONF
|
||||
|
||||
urlpatterns = __import__(project_urls).urls.urlpatterns
|
||||
|
||||
found = False
|
||||
matches_method = False
|
||||
for urlpattern in urlpatterns:
|
||||
regex = urlpattern.regex
|
||||
pattern = regex.pattern
|
||||
actual_method = urlpattern.callback
|
||||
|
||||
if topic.path == pattern:
|
||||
found = True
|
||||
if method == actual_method:
|
||||
matches_method = True
|
||||
|
||||
assert found, "Expected url(%s) to be mapped but it wasn't"
|
||||
if assert_method_as_well:
|
||||
assert matches_method, "Expected url(%s) to match method(%s), but it didn't"
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
|
@ -9,101 +8,35 @@
|
|||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
import django
|
||||
from pyvows import Vows
|
||||
from django.http import HttpRequest
|
||||
|
||||
from django_pyvows import http_helpers
|
||||
from django_pyvows.assertions import Url, Model, Template
|
||||
from django_pyvows.server import DjangoServer
|
||||
from django_pyvows.settings_manager import settings_tracker
|
||||
from django_pyvows.http_helpers import HttpClientSupport
|
||||
from django_pyvows.settings_helpers import SettingsOverrideSupport
|
||||
|
||||
DEFAULT_PORT = 3331
|
||||
DEFAULT_HOST = '127.0.0.1'
|
||||
|
||||
class DjangoContext(Vows.Context):
|
||||
|
||||
@classmethod
|
||||
def start_environment(cls, settings_path):
|
||||
if not settings_path:
|
||||
raise RuntimeError('The settings_path argument is required.')
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = settings_path
|
||||
settings_tracker.install()
|
||||
|
||||
class DjangoContext(Vows.Context, HttpClientSupport, SettingsOverrideSupport):
|
||||
def __init__(self, parent):
|
||||
super(DjangoContext, self).__init__(parent)
|
||||
self.ignore('get_settings', 'template', 'request', 'model', 'url', 'find_in_parent',
|
||||
'start_environment', 'port', 'host', 'get_url', 'get', 'post')
|
||||
|
||||
def setup(self):
|
||||
DjangoContext.start_environment(self.get_settings())
|
||||
HttpClientSupport.__init__(self)
|
||||
SettingsOverrideSupport.__init__(self)
|
||||
|
||||
def get_settings(self):
|
||||
return os.environ.get('DJANGO_SETTINGS_MODULE', 'settings')
|
||||
self.ignore('setup_environment', 'settings_module')
|
||||
|
||||
def url(self, path):
|
||||
return Url(self, path)
|
||||
DjangoContext.setup_environment(self.settings_module())
|
||||
|
||||
def template(self, template_name, context):
|
||||
return Template(template_name, context)
|
||||
def settings_module(self):
|
||||
return 'settings'
|
||||
|
||||
def request(self, **kw):
|
||||
return HttpRequest(**kw)
|
||||
@classmethod
|
||||
def setup_environment(cls, settings_module):
|
||||
if not settings_module:
|
||||
raise ValueError('The settings_path argument is required.')
|
||||
|
||||
def model(self, model_class):
|
||||
return Model(self, model_class)
|
||||
|
||||
def get(self, path):
|
||||
return http_helpers.get(self.get_url(path))
|
||||
|
||||
def post(self, path, params):
|
||||
return http_helpers.post(self.get_url(path), params)
|
||||
|
||||
def find_in_parent(self, attr_name):
|
||||
ctx = self.parent
|
||||
while ctx:
|
||||
if hasattr(ctx, attr_name):
|
||||
return getattr(ctx, attr_name)
|
||||
ctx = ctx.parent
|
||||
raise ValueError('Host could not be found in the context or any of its parents')
|
||||
|
||||
def get_url(self, path):
|
||||
try:
|
||||
return self.find_in_parent('get_url')(path)
|
||||
except ValueError:
|
||||
return path
|
||||
|
||||
|
||||
|
||||
class DjangoHTTPContext(DjangoContext):
|
||||
|
||||
def start_server(self, host=None, port=None, settings={}, threads=1):
|
||||
if not port: port = DEFAULT_PORT
|
||||
if not host: host = DEFAULT_HOST
|
||||
|
||||
self.address = (host, port)
|
||||
self.server = DjangoServer(host, port)
|
||||
self.server.start(settings,threads)
|
||||
|
||||
def __init__(self, parent):
|
||||
super(DjangoHTTPContext, self).__init__(parent)
|
||||
self.ignore('start_server', 'settings')
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
if hasattr(self, 'address'):
|
||||
return self.address[0]
|
||||
return self.find_in_parent('host')
|
||||
|
||||
@property
|
||||
def port(self):
|
||||
if hasattr(self, 'address'):
|
||||
return self.address[1]
|
||||
return self.find_in_parent('port')
|
||||
|
||||
def get_url(self, path):
|
||||
if re.match('^https?:\/\/', path):
|
||||
return path
|
||||
return 'http://%s:%d%s' % (self.host, self.port, path)
|
||||
os.environ.update({'DJANGO_SETTINGS_MODULE': settings_module})
|
||||
django.setup()
|
||||
|
||||
from django.test.utils import setup_test_environment
|
||||
setup_test_environment()
|
||||
|
|
|
@ -1,101 +1,27 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import httplib2
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
import mimetypes
|
||||
import mimetools
|
||||
import itertools
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
class MultiPartForm(object):
|
||||
"""Accumulate the data to be used when posting a form."""
|
||||
|
||||
class HttpClientSupport(object):
|
||||
def __init__(self):
|
||||
self.form_fields = []
|
||||
self.files = []
|
||||
self.boundary = mimetools.choose_boundary()
|
||||
return
|
||||
self._client = None
|
||||
self.ignore('get', 'post')
|
||||
|
||||
def get_content_type(self):
|
||||
return 'multipart/form-data; boundary=%s' % self.boundary
|
||||
@property
|
||||
def client(self):
|
||||
if self._client is None:
|
||||
from django.test.client import Client # Needs to be lazy loaded due settings config
|
||||
self._client = Client()
|
||||
return self._client
|
||||
|
||||
def add_field(self, name, value):
|
||||
"""Add a simple field to the form data."""
|
||||
self.form_fields.append((name, value))
|
||||
return
|
||||
|
||||
def add_file(self, fieldname, filename, fileHandle, mimetype=None):
|
||||
"""Add a file to be uploaded."""
|
||||
body = fileHandle.read()
|
||||
if mimetype is None:
|
||||
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
|
||||
self.files.append((fieldname, filename, mimetype, body))
|
||||
return
|
||||
|
||||
def __str__(self):
|
||||
"""Return a string representing the form data, including attached files."""
|
||||
# Build a list of lists, each containing "lines" of the
|
||||
# request. Each part is separated by a boundary string.
|
||||
# Once the list is built, return a string where each
|
||||
# line is separated by '\r\n'.
|
||||
parts = []
|
||||
part_boundary = '--' + self.boundary
|
||||
|
||||
# Add the form fields
|
||||
parts.extend(
|
||||
[ part_boundary,
|
||||
'Content-Disposition: form-data; name="%s"' % name,
|
||||
'',
|
||||
value,
|
||||
]
|
||||
for name, value in self.form_fields
|
||||
)
|
||||
|
||||
# Add the files to upload
|
||||
parts.extend(
|
||||
[ part_boundary,
|
||||
'Content-Disposition: file; name="%s"; filename="%s"' % \
|
||||
(field_name, filename),
|
||||
'Content-Type: %s' % content_type,
|
||||
'',
|
||||
body,
|
||||
]
|
||||
for field_name, filename, content_type, body in self.files
|
||||
)
|
||||
|
||||
# Flatten the list and add closing boundary marker,
|
||||
# then return CR+LF separated data
|
||||
flattened = list(itertools.chain(*parts))
|
||||
flattened.append('--' + self.boundary + '--')
|
||||
flattened.append('')
|
||||
return '\r\n'.join(flattened)
|
||||
|
||||
|
||||
def get(url):
|
||||
h = httplib2.Http()
|
||||
resp, content = h.request(url)
|
||||
return resp, content
|
||||
|
||||
def post(url, data):
|
||||
h = httplib2.Http()
|
||||
form = MultiPartForm()
|
||||
|
||||
for field, value in data.iteritems():
|
||||
if hasattr(value, "read"):
|
||||
form.add_file(field, value.name, value)
|
||||
else:
|
||||
form.add_field(field, str(value))
|
||||
|
||||
body = str(form)
|
||||
headers = {
|
||||
'Content-type': form.get_content_type(),
|
||||
'Content-length': str(len(body))
|
||||
}
|
||||
|
||||
try:
|
||||
response = h.request(url, 'POST', headers=headers, body=body)
|
||||
except httplib2.HttpLib2Error, err:
|
||||
response = err
|
||||
|
||||
return response
|
||||
def get(self, *args, **kwargs):
|
||||
return self.client.get(*args, **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
return self.client.post(*args, **kwargs)
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from threading import Thread, current_thread, local
|
||||
from time import sleep
|
||||
|
||||
from cherrypy import wsgiserver
|
||||
|
||||
from django.core.handlers.wsgi import WSGIHandler
|
||||
|
||||
|
||||
def run_app(host, port, thread_count):
|
||||
server = wsgiserver.CherryPyWSGIServer(
|
||||
(host, port),
|
||||
WSGIHandler(),
|
||||
server_name='tornado-pyvows',
|
||||
numthreads = thread_count
|
||||
)
|
||||
|
||||
my_thread = current_thread()
|
||||
my_thread.server = server
|
||||
|
||||
try:
|
||||
server.start()
|
||||
except KeyboardInterrupt:
|
||||
server.stop()
|
||||
|
||||
class DjangoServer(object):
|
||||
|
||||
def __init__(self, host, port):
|
||||
self.host = host
|
||||
self.port = port
|
||||
|
||||
def start(self, settings, thread_count=1):
|
||||
self.thr = Thread(target= run_app, args=(self.host, self.port, thread_count))
|
||||
self.thr.daemon = True
|
||||
self.thr.settings = {}
|
||||
for k, v in settings.iteritems():
|
||||
self.thr.settings[k] = v
|
||||
|
||||
self.thr.start()
|
||||
|
||||
while not len(self.thr.server.requests._threads):
|
||||
sleep(0.1)
|
||||
|
||||
for _thread in self.thr.server.requests._threads:
|
||||
_thread.settings = {}
|
||||
for k, v in settings.iteritems():
|
||||
_thread.settings[k] = v
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
|
@ -8,11 +7,11 @@
|
|||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from sandbox.main.models import StringModel
|
||||
class SettingsOverrideSupport(object):
|
||||
def __init__(self):
|
||||
self.ignore('settings')
|
||||
|
||||
class StringModelAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', )
|
||||
|
||||
admin.site.register(StringModel, StringModelAdmin)
|
||||
def settings(self, **kwargs):
|
||||
from django.test.utils import override_settings
|
||||
return override_settings(**kwargs)
|
|
@ -1,44 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from threading import current_thread
|
||||
|
||||
class SettingsTracker(object):
|
||||
|
||||
def install(self):
|
||||
actual_import = __builtins__['__import__']
|
||||
if actual_import != self._import:
|
||||
self.real_import = actual_import
|
||||
__builtins__['__import__'] = self._import
|
||||
|
||||
def _import(self, name, globals=None, locals=None, fromlist=[], level=-1):
|
||||
result = apply(self.real_import, (name, globals, locals, fromlist, level))
|
||||
fromlist = (fromlist or [])
|
||||
if name == 'django.conf' and 'settings' in fromlist:
|
||||
if type(result.settings) != VowsSettings:
|
||||
result.settings = VowsSettings(result.settings)
|
||||
elif name == 'django' and 'conf' in fromlist:
|
||||
if type(result.conf.settings) != VowsSettings:
|
||||
result.conf.settings = VowsSettings(result.conf.settings)
|
||||
return result
|
||||
|
||||
class VowsSettings(object):
|
||||
|
||||
def __init__(self, original_settings):
|
||||
self.original_settings = original_settings
|
||||
|
||||
def __getattr__(self, attr_name):
|
||||
thread = current_thread()
|
||||
if hasattr(thread, 'settings'):
|
||||
if attr_name in thread.settings:
|
||||
return thread.settings[attr_name]
|
||||
return getattr(self.original_settings, attr_name)
|
||||
|
||||
settings_tracker = SettingsTracker()
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
django==1.3.1
|
||||
pyvows
|
||||
Django==1.8.3
|
||||
pyVows==2.0.6
|
||||
coverage==3.5.1
|
||||
httplib2
|
||||
lxml
|
||||
cssselect
|
||||
cherrypy
|
||||
lxml==3.4.4
|
||||
cssselect==0.9.1
|
||||
|
|
0
sandbox/main/__init__.py
Normal file
0
sandbox/main/__init__.py
Normal file
9
sandbox/main/admin.py
Normal file
9
sandbox/main/admin.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from models import StringModel
|
||||
|
||||
|
||||
class StringModelAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', )
|
||||
|
||||
admin.site.register(StringModel, StringModelAdmin)
|
5
sandbox/main/forms.py
Normal file
5
sandbox/main/forms.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django import forms
|
||||
|
||||
|
||||
class NameForm(forms.Form):
|
||||
your_name = forms.CharField(label='Your name', max_length=100, required=True)
|
5
sandbox/main/models.py
Normal file
5
sandbox/main/models.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class StringModel(models.Model):
|
||||
name = models.CharField(max_length=100)
|
|
@ -1,32 +1,43 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
|
||||
from .forms import NameForm
|
||||
|
||||
|
||||
def home(request):
|
||||
return HttpResponse('hello world')
|
||||
|
||||
|
||||
def say_hello(request):
|
||||
SAY_HELLO_WITHOUT_NAME = getattr(settings, "SAY_HELLO_WITHOUT_NAME", False)
|
||||
if 'name' in request.GET:
|
||||
name = request.GET['name']
|
||||
elif SAY_HELLO_WITHOUT_NAME:
|
||||
name = 'guess'
|
||||
name = 'guest'
|
||||
else:
|
||||
return HttpResponse("What's your name?")
|
||||
return HttpResponse("Hello, %s!" % name)
|
||||
|
||||
|
||||
def post_it(request):
|
||||
return HttpResponse(request.POST['value'])
|
||||
|
||||
|
||||
def post_file(request):
|
||||
return HttpResponse(request.FILES['the_file'].read().strip())
|
||||
|
||||
|
||||
def post_name(request):
|
||||
if request.method == 'POST':
|
||||
form = NameForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
return HttpResponseRedirect(
|
||||
'/say/?name={}'.format(form.cleaned_data['your_name']))
|
||||
|
||||
else:
|
||||
form = NameForm()
|
||||
|
||||
return render(request, 'name.html', {'form': form})
|
10
sandbox/manage.py
Executable file
10
sandbox/manage.py
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sandbox.settings")
|
||||
|
||||
from django.core.management import execute_from_command_line
|
||||
|
||||
execute_from_command_line(sys.argv)
|
0
sandbox/sandbox/__init__.py
Normal file
0
sandbox/sandbox/__init__.py
Normal file
95
sandbox/sandbox/settings.py
Normal file
95
sandbox/sandbox/settings.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
"""
|
||||
Django settings for sandbox project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 1.8.3.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.8/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.8/ref/settings/
|
||||
"""
|
||||
import os
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
SECRET_KEY = '+1e*=5h9ri-$#@xmgs*9wrm&@d#li6d9u3e&atmzo5s*6k%_#o'
|
||||
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
'main',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'sandbox.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [
|
||||
os.path.join(BASE_DIR, "templates"),
|
||||
],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'sandbox.wsgi.application'
|
||||
|
||||
# Database
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Internationalization
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# Custom configs
|
||||
SAY_HELLO_WITHOUT_NAME = False
|
11
sandbox/sandbox/urls.py
Normal file
11
sandbox/sandbox/urls.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from django.conf.urls import url
|
||||
from main.views import home, say_hello, post_it, post_file, post_name
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', home, name='home'),
|
||||
url(r'^say/$', say_hello, name='say_hello'),
|
||||
url(r'^post_it/$', post_it, name='post_it'),
|
||||
url(r'^post_file/$', post_file, name='post_file'),
|
||||
url(r'^post-name/$', post_name, name='post_name'),
|
||||
]
|
16
sandbox/sandbox/wsgi.py
Normal file
16
sandbox/sandbox/wsgi.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
WSGI config for sandbox project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sandbox.settings")
|
||||
|
||||
application = get_wsgi_application()
|
5
sandbox/templates/name.html
Normal file
5
sandbox/templates/name.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
<form action="/post-name/" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
<input type="submit" value="Submit" />
|
||||
</form>
|
0
vows/__init__.py
Normal file
0
vows/__init__.py
Normal file
37
vows/assertions_vows.py
Normal file
37
vows/assertions_vows.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from pyvows import Vows, expect
|
||||
|
||||
from test_config import ConfiguredVowsContext as DjangoContext
|
||||
|
||||
|
||||
@Vows.batch
|
||||
class DjangoAssertionsVows(DjangoContext):
|
||||
|
||||
class RedirectsTo(DjangoContext):
|
||||
def topic(self):
|
||||
return self.get("/say")
|
||||
|
||||
def should_redirect(self, topic):
|
||||
expect(topic).redirects_to('/say/', status_code=301)
|
||||
|
||||
class Contains(DjangoContext):
|
||||
def topic(self):
|
||||
return self.get('/say/')
|
||||
|
||||
def should_work(self, topic):
|
||||
expect(topic).contains('name')
|
||||
|
||||
class WithFormError(DjangoContext):
|
||||
def topic(self):
|
||||
return self.post('/post-name/', {'another_field': 'filled'})
|
||||
|
||||
def should_work(self, topic):
|
||||
expect(topic).with_form_error('form', 'your_name', 'This field is required.')
|
55
vows/client_vows.py
Normal file
55
vows/client_vows.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from pyvows import Vows, expect
|
||||
|
||||
from test_config import ConfiguredVowsContext as DjangoContext
|
||||
|
||||
|
||||
@Vows.batch
|
||||
class DjangoHTTPTestClientCompatibilityVows(DjangoContext):
|
||||
|
||||
class SimpleGet(DjangoContext):
|
||||
def topic(self):
|
||||
return self.get('/say/')
|
||||
|
||||
def should_be_ok(self, topic):
|
||||
expect(topic.status_code).to_equal(200)
|
||||
|
||||
def should_ask_for_my_name(self, topic):
|
||||
expect(topic).contains('What\'s your name?')
|
||||
|
||||
class SimpleGetWithParams(DjangoContext):
|
||||
def topic(self):
|
||||
return self.get('/say/?name=Rafael')
|
||||
|
||||
def should_say_hello_to_me(self, topic):
|
||||
expect(topic).contains('Hello, Rafael!')
|
||||
|
||||
class SimplePost(DjangoContext):
|
||||
def topic(self):
|
||||
return self.post('/post_it/', {'value': 'posted!'})
|
||||
|
||||
def should_be_posted(self, topic):
|
||||
expect(topic).contains('posted!')
|
||||
|
||||
class PostFile(DjangoContext):
|
||||
def topic(self):
|
||||
return self.post('/post_file/', {'the_file': open(self.TEST_FILE_PATH)})
|
||||
|
||||
def should_be_posted_to_the_server(self, topic):
|
||||
expect(topic).contains("the contents")
|
||||
|
||||
class WhenNotFound(DjangoContext):
|
||||
def topic(self):
|
||||
return self.post('/post_/', {'the_file': open(self.TEST_FILE_PATH)})
|
||||
|
||||
def should_be_404(self, topic):
|
||||
expect(topic.status_code).to_equal(404)
|
|
@ -9,109 +9,23 @@
|
|||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from pyvows import Vows, expect
|
||||
from pyvows.decorators import capture_error
|
||||
|
||||
from django_pyvows.context import DjangoContext
|
||||
|
||||
from django_pyvows.context import DjangoContext, DjangoHTTPContext
|
||||
|
||||
@Vows.batch
|
||||
class ContextTest(Vows.Context):
|
||||
|
||||
@capture_error
|
||||
def topic(self):
|
||||
return DjangoContext.start_environment(None)
|
||||
return DjangoContext.setup_environment(None)
|
||||
|
||||
def should_be_an_error(self, topic):
|
||||
expect(topic).to_be_an_error()
|
||||
|
||||
def should_be_runtime_error(self, topic):
|
||||
expect(topic).to_be_an_error_like(RuntimeError)
|
||||
expect(topic).to_be_an_error_like(ValueError)
|
||||
|
||||
def should_have_nice_error_message(self, topic):
|
||||
expect(topic).to_have_an_error_message_of('The settings_path argument is required.')
|
||||
|
||||
class WithinANoDjangoContext(Vows.Context):
|
||||
|
||||
class TheGetUrlMethod(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.get_url('/')
|
||||
|
||||
def should_return_the_same_path(self, topic):
|
||||
expect(topic).to_equal('/')
|
||||
|
||||
class TheHost(DjangoHTTPContext):
|
||||
|
||||
def topic(self):
|
||||
return self.host
|
||||
|
||||
def should_return_an_error(self, topic):
|
||||
expect(topic).to_be_an_error_like(ValueError)
|
||||
|
||||
class ThePort(DjangoHTTPContext):
|
||||
|
||||
def topic(self):
|
||||
return self.port
|
||||
|
||||
def should_return_an_error(self, topic):
|
||||
expect(topic).to_be_an_error_like(ValueError)
|
||||
|
||||
class WithinAServer(DjangoHTTPContext):
|
||||
|
||||
def setup(self):
|
||||
self.start_server(port=8085)
|
||||
|
||||
def should_default_to_one_thread(self,topic):
|
||||
expect(self.server.thr.server._get_numthreads()).to_equal(1)
|
||||
|
||||
class WithinDjangoHTTPContextTheGetUrlMethod(DjangoHTTPContext):
|
||||
|
||||
def topic(self):
|
||||
return self.get_url('http://127.0.0.1:8085/complete_url/')
|
||||
|
||||
def when_passed_a_complete_url_should_return_the_url_without_modification(self, topic):
|
||||
expect(topic).to_equal('http://127.0.0.1:8085/complete_url/')
|
||||
|
||||
class InADjangoHTTPContext(DjangoHTTPContext):
|
||||
|
||||
def topic(self):
|
||||
return self.get_url('/')
|
||||
|
||||
def the_get_url_should_return_a_well_formed_url(self, topic):
|
||||
expect(topic).to_equal('http://127.0.0.1:8085/')
|
||||
|
||||
class ANoDjangoContext(Vows.Context):
|
||||
|
||||
class TheHost(DjangoHTTPContext):
|
||||
|
||||
def topic(self):
|
||||
return self.host
|
||||
|
||||
def should_be_equal_to_the_host_in_out_context(self, topic):
|
||||
expect(topic).to_equal('127.0.0.1')
|
||||
|
||||
class ThePort(DjangoHTTPContext):
|
||||
|
||||
def topic(self):
|
||||
return self.port
|
||||
|
||||
def should_be_equal_to_the_port_in_out_context(self, topic):
|
||||
expect(topic).to_equal(8085)
|
||||
|
||||
class AnDjangoContext(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.get_url('/')
|
||||
|
||||
def the_get_url_method_should_return_a_well_formed_url(self, topic):
|
||||
expect(topic).to_equal('http://127.0.0.1:8085/')
|
||||
|
||||
class WithinAMultiThreadedServer(DjangoHTTPContext):
|
||||
|
||||
def setup(self):
|
||||
self.start_server(threads=5)
|
||||
|
||||
def topic(self):
|
||||
return self.server
|
||||
|
||||
def should_allow_user_to_specify_number_of_threads(self,topic):
|
||||
expect(topic.thr.server._get_numthreads()).to_equal(5)
|
||||
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from pyvows import Vows, expect
|
||||
from django_pyvows.context import DjangoContext
|
||||
|
||||
DjangoContext.start_environment("sandbox.settings")
|
||||
|
||||
from django.db import models
|
||||
from sandbox.main.models import StringModel
|
||||
|
||||
@Vows.batch
|
||||
class ModelVows(DjangoContext):
|
||||
|
||||
class MainModel(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.model(StringModel)
|
||||
|
||||
def should_be_cruddable_when_model_only_has_a_string(self, topic):
|
||||
expect(topic).to_be_cruddable()
|
||||
|
||||
def should_be_cruddable_when_string_passed(self, topic):
|
||||
expect(topic).to_be_cruddable({
|
||||
'name': 'something'
|
||||
})
|
||||
|
||||
def should_be_possible_to_use_the_assertion_in_model_instance(self, topic):
|
||||
expect(topic).to_have_field('name')
|
||||
|
||||
def should_have_a_method_to_call(self, topic):
|
||||
expect(hasattr(topic, '__call__')).to_be_true()
|
||||
|
||||
class WhenICreateANewInstance(DjangoContext):
|
||||
|
||||
def topic(self, model):
|
||||
return model()
|
||||
|
||||
def should_be_an_instance_of_django_model_class(self, topic):
|
||||
expect(isinstance(topic, models.Model)).to_be_true()
|
||||
|
||||
def should_have_a_name_field(self, topic):
|
||||
expect(topic).to_have_field('name')
|
||||
|
||||
def should_have_a_name_field_as_charfield(self, topic):
|
||||
expect(topic).to_have_field('name', models.CharField)
|
||||
|
||||
def should_have_a_name_field_as_charfield_and_max_length_100(self, topic):
|
||||
expect(topic).to_have_field('name', models.CharField, max_length=100)
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from django.db import models
|
||||
|
||||
class StringModel(models.Model):
|
||||
name = models.CharField(max_length=100)
|
|
@ -1,16 +0,0 @@
|
|||
"""
|
||||
This file demonstrates writing tests using the unittest module. These will pass
|
||||
when you run "manage.py test".
|
||||
|
||||
Replace this with more appropriate tests for your application.
|
||||
"""
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
"""
|
||||
self.assertEqual(1 + 1, 2)
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from django.core.management import execute_manager
|
||||
import imp
|
||||
try:
|
||||
imp.find_module('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" % __file__)
|
||||
sys.exit(1)
|
||||
|
||||
import settings
|
||||
|
||||
if __name__ == "__main__":
|
||||
execute_manager(settings)
|
|
@ -1,153 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
# Django settings for sandbox project.
|
||||
|
||||
import os.path
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
PROJECT_ROOT = os.path.realpath(os.path.dirname(__file__))
|
||||
|
||||
ADMINS = (
|
||||
# ('Your Name', 'your_email@example.com'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
|
||||
'PORT': '', # Set to empty string for default. Not used with sqlite3.
|
||||
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
||||
'NAME': 'db.db', # Or path to database file if using sqlite3.
|
||||
'USER': 'root', # Not used with sqlite3.
|
||||
'PASSWORD': '', # Not used with sqlite3.
|
||||
}
|
||||
}
|
||||
|
||||
# Local time zone for this installation. Choices can be found here:
|
||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||
# although not all choices may be available on all operating systems.
|
||||
# On Unix systems, a value of None will cause Django to use the same
|
||||
# timezone as the operating system.
|
||||
# If running in a Windows environment this must be set to the same as your
|
||||
# system time zone.
|
||||
TIME_ZONE = 'America/Chicago'
|
||||
|
||||
# Language code for this installation. All choices can be found here:
|
||||
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# If you set this to False, Django will make some optimizations so as not
|
||||
# to load the internationalization machinery.
|
||||
USE_I18N = True
|
||||
|
||||
# If you set this to False, Django will not format dates, numbers and
|
||||
# calendars according to the current locale
|
||||
USE_L10N = True
|
||||
|
||||
# Absolute filesystem path to the directory that will hold user-uploaded files.
|
||||
# Example: "/home/media/media.lawrence.com/media/"
|
||||
MEDIA_ROOT = ''
|
||||
|
||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||
# trailing slash.
|
||||
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
|
||||
MEDIA_URL = ''
|
||||
|
||||
# Absolute path to the directory static files should be collected to.
|
||||
# Don't put anything in this directory yourself; store your static files
|
||||
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
|
||||
# Example: "/home/media/media.lawrence.com/static/"
|
||||
STATIC_ROOT = ''
|
||||
|
||||
# URL prefix for static files.
|
||||
# Example: "http://media.lawrence.com/static/"
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# URL prefix for admin static files -- CSS, JavaScript and images.
|
||||
# Make sure to use a trailing slash.
|
||||
# Examples: "http://foo.com/static/admin/", "/static/admin/".
|
||||
ADMIN_MEDIA_PREFIX = '/static/admin/'
|
||||
|
||||
# Additional locations of static files
|
||||
STATICFILES_DIRS = (
|
||||
# Put strings here, like "/home/html/static" or "C:/www/django/static".
|
||||
# Always use forward slashes, even on Windows.
|
||||
# Don't forget to use absolute paths, not relative paths.
|
||||
)
|
||||
|
||||
# List of finder classes that know how to find static files in
|
||||
# various locations.
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
)
|
||||
|
||||
# Make this unique, and don't share it with anybody.
|
||||
SECRET_KEY = 'l7#du3ceob9^i^6^jambl@io7nxc^%&))b$uxlxa#-3lake5+w'
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'sandbox.urls'
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
|
||||
# Always use forward slashes, even on Windows.
|
||||
# Don't forget to use absolute paths, not relative paths.
|
||||
os.path.join(PROJECT_ROOT, "templates"),
|
||||
)
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'sandbox.main',
|
||||
# Uncomment the next line to enable the admin:
|
||||
# 'django.contrib.admin',
|
||||
# Uncomment the next line to enable admin documentation:
|
||||
# 'django.contrib.admindocs',
|
||||
)
|
||||
|
||||
SAY_HELLO_WITHOUT_NAME = False
|
||||
|
||||
# A sample logging configuration. The only tangible logging
|
||||
# performed by this configuration is to send an email to
|
||||
# the site admins on every HTTP 500 error.
|
||||
# See http://docs.djangoproject.com/en/dev/topics/logging for
|
||||
# more details on how to customize your logging configuration.
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'handlers': {
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'class': 'django.utils.log.AdminEmailHandler'
|
||||
}
|
||||
},
|
||||
'loggers': {
|
||||
'django.request': {
|
||||
'handlers': ['mail_admins'],
|
||||
'level': 'ERROR',
|
||||
'propagate': True,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from django.conf.urls.defaults import patterns, include, url
|
||||
|
||||
# Uncomment the next two lines to enable the admin:
|
||||
from django.contrib import admin
|
||||
admin.autodiscover()
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', 'sandbox.main.views.home', name='home'),
|
||||
url(r'^say/$', 'sandbox.main.views.say_hello', name='say_hello'),
|
||||
url(r'^post_it/$', 'sandbox.main.views.post_it', name='post_it'),
|
||||
url(r'^post_file/$', 'sandbox.main.views.post_file', name='post_file'),
|
||||
|
||||
# url(r'^sandbox/', include('sandbox.foo.urls')),
|
||||
|
||||
# Uncomment the admin/doc line below to enable admin documentation:
|
||||
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
|
||||
# Uncomment the next line to enable the admin:
|
||||
#url(r'^admin/', include('admin.site.urls')),
|
||||
)
|
|
@ -1,83 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from os.path import abspath, join, dirname
|
||||
|
||||
import httplib2
|
||||
|
||||
from django_pyvows.context import DjangoContext, DjangoHTTPContext
|
||||
from django_pyvows.assertions import *
|
||||
|
||||
TEST_FILE_PATH = abspath(join(dirname(__file__), 'fixtures/the_file.txt'))
|
||||
|
||||
DjangoContext.start_environment("sandbox.settings")
|
||||
|
||||
@Vows.batch
|
||||
class HttpContextVows(DjangoHTTPContext):
|
||||
|
||||
def topic(self):
|
||||
self.start_server()
|
||||
return self.get("/")
|
||||
|
||||
def the_return_code_should_be_200(self, (topic, content)):
|
||||
expect(topic.status).to_equal(200)
|
||||
|
||||
def should_return_the_success_response(self, (topic, content)):
|
||||
expect(content).to_equal("hello world")
|
||||
|
||||
class Methods(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.get('/?name=rafael')
|
||||
|
||||
def should_be_possible_to_pass_get_parameters(self, (topic, content)):
|
||||
expect(topic.status).to_equal(200)
|
||||
|
||||
class AskMyName(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.get('/say/')
|
||||
|
||||
def should_ask_for_my_name(self, (topic, content)):
|
||||
expect(content).to_equal('What\'s your name?')
|
||||
|
||||
class SayHelloToMe(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.get('/say/?name=Rafael')
|
||||
|
||||
def should_say_hello_to_me(self, (topic, content)):
|
||||
expect(content).to_equal('Hello, Rafael!')
|
||||
|
||||
class PostIt(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.post('/post_it/', {'value': 'posted!'})
|
||||
|
||||
def should_be_posted(self, (topic, content)):
|
||||
expect(content).to_equal('posted!')
|
||||
|
||||
class PostFile(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.post('/post_file/', {'the_file': open(TEST_FILE_PATH) })
|
||||
|
||||
def should_be_posted_to_the_server(self, (topic, content)):
|
||||
expect(content).to_equal("the contents")
|
||||
|
||||
class PostToNotFound(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.post('/post_/', {'the_file': open(TEST_FILE_PATH) })
|
||||
|
||||
def should_be_404(self, (topic, content)):
|
||||
expect(topic.status).to_equal(404)
|
||||
|
||||
|
|
@ -9,73 +9,40 @@
|
|||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from pyvows import Vows, expect
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from django_pyvows.context import DjangoContext, DjangoHTTPContext
|
||||
from django_pyvows.settings_manager import settings_tracker, VowsSettings
|
||||
from test_config import ConfiguredVowsContext as DjangoContext
|
||||
|
||||
DjangoContext.start_environment("sandbox.settings")
|
||||
|
||||
@Vows.batch
|
||||
class SettingsVows(DjangoContext):
|
||||
|
||||
class WhenIUseTheSettingsTracker(DjangoContext):
|
||||
class SettingsOverridingVows(DjangoContext):
|
||||
|
||||
class CannotSayHelloWithoutName(DjangoContext):
|
||||
def topic(self):
|
||||
settings_tracker.install()
|
||||
with self.settings(SAY_HELLO_WITHOUT_NAME=False):
|
||||
return self.get('/say/')
|
||||
|
||||
class WhenImportFromDjangoConf(DjangoContext):
|
||||
def should_be_ok(self, topic):
|
||||
expect(topic.status_code).to_equal(200)
|
||||
|
||||
def topic(self):
|
||||
from django.conf import settings
|
||||
return settings
|
||||
|
||||
def should_be_the_vows_settings(self, topic):
|
||||
expect(topic).to_be_instance_of(VowsSettings)
|
||||
|
||||
class WhenIImportOnlyConfAndThenUseSettings(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
from django import conf
|
||||
return conf.settings
|
||||
|
||||
def should_be_the_vows_settings(self, topic):
|
||||
expect(topic).to_be_instance_of(VowsSettings)
|
||||
|
||||
class WhenIImportTheCompletePathAndThenUseSettings(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
import django.conf
|
||||
return django.conf.settings
|
||||
|
||||
def should_be_the_vows_settings(self, topic):
|
||||
expect(topic).to_be_instance_of(VowsSettings)
|
||||
|
||||
class CannotSayHelloWithoutName(DjangoHTTPContext):
|
||||
def should_ask_for_my_name(self, topic):
|
||||
expect(topic).contains("What's your name?")
|
||||
|
||||
class SayHelloWithoutName(DjangoContext):
|
||||
def topic(self):
|
||||
self.start_server(port=9000, settings={
|
||||
'SAY_HELLO_WITHOUT_NAME': False
|
||||
})
|
||||
with self.settings(SAY_HELLO_WITHOUT_NAME=True):
|
||||
return self.get('/say/')
|
||||
|
||||
def should_be_ok(self, topic):
|
||||
expect(topic.status_code).to_equal(200)
|
||||
|
||||
def should_(self, topic):
|
||||
expect(topic).contains("Hello, guest!")
|
||||
|
||||
class UseDecoratorToChangeSettings(DjangoContext):
|
||||
@override_settings(SAY_HELLO_WITHOUT_NAME=True)
|
||||
def topic(self):
|
||||
return self.get('/say/')
|
||||
|
||||
def should_be_ok(self, (topic, content)):
|
||||
expect(topic.status).to_equal(200)
|
||||
|
||||
def should_ask_for_my_name(self, (topic, content)):
|
||||
expect(content).to_equal("What's your name?")
|
||||
|
||||
class SayHelloWithoutName(DjangoHTTPContext):
|
||||
|
||||
def topic(self):
|
||||
self.start_server(port=9001, settings={
|
||||
'SAY_HELLO_WITHOUT_NAME': True
|
||||
})
|
||||
return self.get('/say/')
|
||||
|
||||
def should_be_ok(self, (topic, content)):
|
||||
expect(topic.status).to_equal(200)
|
||||
|
||||
def should_(self, (topic, content)):
|
||||
expect(content).to_equal("Hello, guess!")
|
||||
|
||||
def should_say_hello_to_guest(self, topic):
|
||||
expect(topic).contains("Hello, guest!")
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from pyvows import Vows, expect
|
||||
|
||||
from django_pyvows.context import DjangoContext
|
||||
from django_pyvows.assertions import *
|
||||
|
||||
@Vows.batch
|
||||
class TemplateVows(DjangoContext):
|
||||
|
||||
def get_settings(self):
|
||||
return 'sandbox.settings'
|
||||
|
||||
class IndexTemplate(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.template('index.html', {
|
||||
'some': 'thing'
|
||||
})
|
||||
|
||||
def should_have_container_div(self, topic):
|
||||
expect(topic).to_contain('div.container')
|
||||
|
||||
def should_not_have_a_hello_div(self, topic):
|
||||
expect(topic).Not.to_contain('div.hello')
|
||||
|
||||
def should_be_index_file(self, topic):
|
||||
expect(unicode(topic)).to_equal('index.html')
|
||||
|
||||
class Paragraph(DjangoContext):
|
||||
|
||||
def topic(self, template):
|
||||
return template.get_text('p.my-text')
|
||||
|
||||
def should_have_paragraph_with_text(self, topic):
|
||||
expect(topic).to_be_like('some text')
|
||||
|
||||
|
20
vows/test_config.py
Normal file
20
vows/test_config.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from os.path import abspath, join, dirname
|
||||
|
||||
from django_pyvows.context import DjangoContext
|
||||
|
||||
|
||||
class ConfiguredVowsContext(DjangoContext):
|
||||
def settings_module(self):
|
||||
return 'sandbox.settings'
|
||||
|
||||
def setup(self):
|
||||
self.TEST_FILE_PATH = abspath(join(dirname(__file__), 'fixtures/the_file.txt'))
|
|
@ -1,32 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from pyvows import Vows, expect
|
||||
|
||||
from django_pyvows.context import DjangoContext
|
||||
from django_pyvows.assertions import *
|
||||
|
||||
DjangoContext.start_environment("sandbox.settings")
|
||||
|
||||
from sandbox.main.views import home
|
||||
|
||||
@Vows.batch
|
||||
class UrlVows(DjangoContext):
|
||||
|
||||
class Home(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return self.url('^$')
|
||||
|
||||
def should_have_home_url_mapped(self, topic):
|
||||
expect(topic).to_be_mapped()
|
||||
|
||||
def should_have_url_mapped_to_home_view(self, topic):
|
||||
expect(topic).to_match_view(home)
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# django-pyvows extensions
|
||||
# https://github.com/rafaelcaricio/django-pyvows
|
||||
|
||||
# Licensed under the MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license
|
||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||
|
||||
from pyvows import Vows, expect
|
||||
from django_pyvows.context import DjangoContext
|
||||
|
||||
DjangoContext.start_environment("sandbox.settings")
|
||||
|
||||
from sandbox.main.views import home
|
||||
|
||||
@Vows.batch
|
||||
class ViewVows(DjangoContext):
|
||||
|
||||
class Home(DjangoContext):
|
||||
|
||||
def topic(self):
|
||||
return home(self.request())
|
||||
|
||||
def should_be_instance_of_http_response(self, topic):
|
||||
expect(topic).to_be_http_response()
|
||||
|
||||
def should_be_hello_world(self, topic):
|
||||
expect(topic).to_have_contents_of('Hello World')
|
Reference in a new issue