Merge pull request #13 from rafaelcaricio/django-1.8-support

Django 1.8 support / Project revamp
This commit is contained in:
Rafael Caricio 2015-07-20 09:57:38 +02:00
commit 4b2926615c
46 changed files with 442 additions and 1224 deletions

1
.gitignore vendored
View file

@ -10,3 +10,4 @@ dist/
.project
.pydevproject
build/
*.sqlite3

View file

@ -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

View file

@ -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

View file

@ -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

View 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)

View file

@ -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 *

View file

@ -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

View file

@ -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)

View file

@ -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"

View file

@ -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()

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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()

View file

@ -1,4 +1,3 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# django-pyvows extensions

View file

@ -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
View file

9
sandbox/main/admin.py Normal file
View 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
View 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
View file

@ -0,0 +1,5 @@
from django.db import models
class StringModel(models.Model):
name = models.CharField(max_length=100)

View file

@ -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
View 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)

View file

View 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
View 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
View 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()

View 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
View file

37
vows/assertions_vows.py Normal file
View 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
View 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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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,
},
}
}

View file

@ -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')),
)

View file

@ -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)

View file

@ -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!")

View file

@ -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
View 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'))

View file

@ -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)

View file

@ -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')