Kaydet (Commit) 440a2a97 authored tarafından Jacob Kaplan-Moss's avatar Jacob Kaplan-Moss

Added framework for writing non-model-based tests, and added tests for cache and templates

from the old django/tests location (which has been removed).


git-svn-id: http://code.djangoproject.com/svn/django/trunk@367 bcc190cf-cafb-0310-a4f2-bffc1f526a37
üst 8483f0aa
"""
Unit tests for django.core.cache
If you don't have memcached running on localhost port 11211, the memcached tests
will fail.
"""
from django.core import cache
import unittest
import time
# functions/classes for complex data type tests
def f():
return 42
class C:
def m(n):
return 24
class CacheBackendsTest(unittest.TestCase):
def testBackends(self):
sc = cache.get_cache('simple://')
mc = cache.get_cache('memcached://127.0.0.1:11211/')
self.failUnless(isinstance(sc, cache._SimpleCache))
self.failUnless(isinstance(mc, cache._MemcachedCache))
def testInvalidBackends(self):
self.assertRaises(cache.InvalidCacheBackendError, cache.get_cache, 'nothing://foo/')
self.assertRaises(cache.InvalidCacheBackendError, cache.get_cache, 'not a uri')
def testDefaultTimeouts(self):
sc = cache.get_cache('simple:///?timeout=15')
mc = cache.get_cache('memcached://127.0.0.1:11211/?timeout=15')
self.assertEquals(sc.default_timeout, 15)
self.assertEquals(sc.default_timeout, 15)
class SimpleCacheTest(unittest.TestCase):
def setUp(self):
self.cache = cache.get_cache('simple://')
def testGetSet(self):
self.cache.set('key', 'value')
self.assertEqual(self.cache.get('key'), 'value')
def testNonExistantKeys(self):
self.assertEqual(self.cache.get('does not exist'), None)
self.assertEqual(self.cache.get('does not exist', 'bang!'), 'bang!')
def testGetMany(self):
self.cache.set('a', 'a')
self.cache.set('b', 'b')
self.cache.set('c', 'c')
self.cache.set('d', 'd')
self.assertEqual(self.cache.get_many(['a', 'c', 'd']), {'a' : 'a', 'c' : 'c', 'd' : 'd'})
self.assertEqual(self.cache.get_many(['a', 'b', 'e']), {'a' : 'a', 'b' : 'b'})
def testDelete(self):
self.cache.set('key1', 'spam')
self.cache.set('key2', 'eggs')
self.assertEqual(self.cache.get('key1'), 'spam')
self.cache.delete('key1')
self.assertEqual(self.cache.get('key1'), None)
self.assertEqual(self.cache.get('key2'), 'eggs')
def testHasKey(self):
self.cache.set('hello', 'goodbye')
self.assertEqual(self.cache.has_key('hello'), True)
self.assertEqual(self.cache.has_key('goodbye'), False)
def testDataTypes(self):
items = {
'string' : 'this is a string',
'int' : 42,
'list' : [1, 2, 3, 4],
'tuple' : (1, 2, 3, 4),
'dict' : {'A': 1, 'B' : 2},
'function' : f,
'class' : C,
}
for (key, value) in items.items():
self.cache.set(key, value)
self.assertEqual(self.cache.get(key), value)
def testExpiration(self):
self.cache.set('expire', 'very quickly', 1)
time.sleep(2)
self.assertEqual(self.cache.get('expire'), None)
def testCull(self):
c = cache.get_cache('simple://?max_entries=9&cull_frequency=3')
for i in range(10):
c.set('culltest%i' % i, i)
n = 0
for i in range(10):
if c.get('culltest%i' % i):
n += 1
self.assertEqual(n, 6)
def testCullAll(self):
c = cache.get_cache('simple://?max_entries=9&cull_frequency=0')
for i in range(10):
c.set('cullalltest%i' % i, i)
for i in range(10):
self.assertEqual(self.cache.get('cullalltest%i' % i), None)
class MemcachedCacheTest(SimpleCacheTest):
def setUp(self):
self.cache = cache.get_cache('memcached://127.0.0.1:11211/')
testCull = testCullAll = lambda s: None
def tests():
s = unittest.TestLoader().loadTestsFromName(__name__)
unittest.TextTestRunner(verbosity=0).run(s)
if __name__ == "__main__":
tests()
from django.core import template, template_loader
# SYNTAX --
# 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class)
TEMPLATE_TESTS = {
# Standard template with no inheritance
'test01': ("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}", {}, '1_3_'),
# Standard two-level inheritance
'test02': ("{% extends 'test01' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),
# Three-level with no redefinitions on third level
'test03': ("{% extends 'test02' %}", {}, '1234'),
# Two-level with no redefinitions on second level
'test04': ("{% extends 'test01' %}", {}, '1_3_'),
# Two-level with double quotes instead of single quotes
'test05': ('{% extends "test02" %}', {}, '1234'),
# Three-level with variable parent-template name
'test06': ("{% extends foo %}", {'foo': 'test02'}, '1234'),
# Two-level with one block defined, one block not defined
'test07': ("{% extends 'test01' %}{% block second %}5{% endblock %}", {}, '1_35'),
# Three-level with one block defined on this level, two blocks defined next level
'test08': ("{% extends 'test02' %}{% block second %}5{% endblock %}", {}, '1235'),
# Three-level with second and third levels blank
'test09': ("{% extends 'test04' %}", {}, '1_3_'),
# Three-level with space NOT in a block -- should be ignored
'test10': ("{% extends 'test04' %} ", {}, '1_3_'),
# Three-level with both blocks defined on this level, but none on second level
'test11': ("{% extends 'test04' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),
# Three-level with this level providing one and second level providing the other
'test12': ("{% extends 'test07' %}{% block first %}2{% endblock %}", {}, '1235'),
# Three-level with this level overriding second level
'test13': ("{% extends 'test02' %}{% block first %}a{% endblock %}{% block second %}b{% endblock %}", {}, '1a3b'),
# A block defined only in a child template shouldn't be displayed
'test14': ("{% extends 'test01' %}{% block newblock %}NO DISPLAY{% endblock %}", {}, '1_3_'),
# A block within another block
'test15': ("{% extends 'test01' %}{% block first %}2{% block inner %}inner{% endblock %}{% endblock %}", {}, '12inner3_'),
# A block within another block (level 2)
'test16': ("{% extends 'test15' %}{% block inner %}out{% endblock %}", {}, '12out3_'),
# {% load %} tag (parent -- setup for test-exception04)
'test17': ("{% load polls.polls %}{% block first %}1234{% endblock %}", {}, '1234'),
# {% load %} tag (standard usage, without inheritance)
'test18': ("{% load polls.polls %}{% voteratio choice poll 400 %}5678", {}, '05678'),
# {% load %} tag (within a child template)
'test19': ("{% extends 'test01' %}{% block first %}{% load polls.polls %}{% voteratio choice poll 400 %}5678{% endblock %}", {}, '1056783_'),
# Raise exception for invalid template name
'test-exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError),
# Raise exception for invalid template name (in variable)
'test-exception02': ("{% extends nonexistent %}", {}, template.TemplateSyntaxError),
# Raise exception for extra {% extends %} tags
'test-exception03': ("{% extends 'test01' %}{% block first %}2{% endblock %}{% extends 'test16' %}", {}, template.TemplateSyntaxError),
# Raise exception for custom tags used in child with {% load %} tag in parent, not in child
'test-exception04': ("{% extends 'test17' %}{% block first %}{% votegraph choice poll 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError),
}
# This replaces the standard template_loader.
def test_template_loader(template_name):
try:
return TEMPLATE_TESTS[template_name][0]
except KeyError:
raise template.TemplateDoesNotExist, template_name
template_loader.load_template_source = test_template_loader
def run_tests():
tests = TEMPLATE_TESTS.items()
tests.sort()
for name, vals in tests:
try:
output = template_loader.get_template(name).render(template.Context(vals[1]))
except Exception, e:
if e.__class__ == vals[2]:
print "%s -- Passed" % name
else:
print "%s -- FAILED. Got %s, exception: %s" % (name, e.__class__, e)
continue
if output == vals[2]:
print "%s -- Passed" % name
else:
print "%s -- FAILED. Expected %r, got %r" % (name, vals[2], output)
if __name__ == "__main__":
run_tests()
This diff is collapsed.
# Unit tests for cache framework
# Uses whatever cache backend is set in the test settings file.
from django.core.cache import cache
import time
# functions/classes for complex data type tests
def f():
return 42
class C:
def m(n):
return 24
# simple set/get
cache.set("key", "value")
assert cache.get("key") == "value"
# get with non-existant keys
assert cache.get("does not exist") is None
assert cache.get("does not exist", "bang!") == "bang!"
# get_many
cache.set('a', 'a')
cache.set('b', 'b')
cache.set('c', 'c')
cache.set('d', 'd')
assert cache.get_many(['a', 'c', 'd']) == {'a' : 'a', 'c' : 'c', 'd' : 'd'}
assert cache.get_many(['a', 'b', 'e']) == {'a' : 'a', 'b' : 'b'}
# delete
cache.set("key1", "spam")
cache.set("key2", "eggs")
assert cache.get("key1") == "spam"
cache.delete("key1")
assert cache.get("key1") is None
assert cache.get("key2") == "eggs"
# has_key
cache.set("hello", "goodbye")
assert cache.has_key("hello") == True
assert cache.has_key("goodbye") == False
# test data types
stuff = {
'string' : 'this is a string',
'int' : 42,
'list' : [1, 2, 3, 4],
'tuple' : (1, 2, 3, 4),
'dict' : {'A': 1, 'B' : 2},
'function' : f,
'class' : C,
}
for (key, value) in stuff.items():
cache.set(key, value)
assert cache.get(key) == value
# expiration
cache.set('expire', 'very quickly', 1)
time.sleep(2)
assert cache.get("expire") == None
\ No newline at end of file
from django.core import template, template_loader
# Helper objects for template tests
class SomeClass:
def __init__(self):
self.otherclass = OtherClass()
def method(self):
return "SomeClass.method"
def method2(self, o):
return o
class OtherClass:
def method(self):
return "OtherClass.method"
# SYNTAX --
# 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class)
TEMPLATE_TESTS = {
### BASIC SYNTAX ##########################################################
# Plain text should go through the template parser untouched
'basic-syntax01': ("something cool", {}, "something cool"),
# Variables should be replaced with their value in the current context
'basic-syntax02': ("{{ headline }}", {'headline':'Success'}, "Success"),
# More than one replacement variable is allowed in a template
'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"),
# Fail silently when a variable is not found in the current context
'basic-syntax04': ("as{{ missing }}df", {}, "asdf"),
# A variable may not contain more than one word
'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError),
# Raise TemplateSyntaxError for empty variable tags
'basic-syntax07': ("{{ }}", {}, template.TemplateSyntaxError),
'basic-syntax08': ("{{ }}", {}, template.TemplateSyntaxError),
# Attribute syntax allows a template to call an object's attribute
'basic-syntax09': ("{{ var.method }}", {"var": SomeClass()}, "SomeClass.method"),
# Multiple levels of attribute access are allowed
'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"),
# Fail silently when a variable's attribute isn't found
'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, ""),
# Raise TemplateSyntaxError when trying to access a variable beginning with an underscore
'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError),
# Raise TemplateSyntaxError when trying to access a variable containing an illegal character
'basic-syntax13': ("{{ va>r }}", {}, template.TemplateSyntaxError),
'basic-syntax14': ("{{ (var.r) }}", {}, template.TemplateSyntaxError),
'basic-syntax15': ("{{ sp%am }}", {}, template.TemplateSyntaxError),
'basic-syntax16': ("{{ eggs! }}", {}, template.TemplateSyntaxError),
'basic-syntax17': ("{{ moo? }}", {}, template.TemplateSyntaxError),
# Attribute syntax allows a template to call a dictionary key's value
'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"),
# Fail silently when a variable's dictionary key isn't found
'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, ""),
# Fail silently when accessing a non-simple method
'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, ""),
# Basic filter usage
'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"),
# Chained filters
'basic-syntax22': ("{{ var|upper|lower }}", {"var": "Django is the greatest!"}, "django is the greatest!"),
# Raise TemplateSyntaxError for space between a variable and filter pipe
'basic-syntax23': ("{{ var |upper }}", {}, template.TemplateSyntaxError),
# Raise TemplateSyntaxError for space after a filter pipe
'basic-syntax24': ("{{ var| upper }}", {}, template.TemplateSyntaxError),
# Raise TemplateSyntaxError for a nonexistent filter
'basic-syntax25': ("{{ var|does_not_exist }}", {}, template.TemplateSyntaxError),
# Raise TemplateSyntaxError when trying to access a filter containing an illegal character
'basic-syntax26': ("{{ var|fil(ter) }}", {}, template.TemplateSyntaxError),
# Raise TemplateSyntaxError for invalid block tags
'basic-syntax27': ("{% nothing_to_see_here %}", {}, template.TemplateSyntaxError),
# Raise TemplateSyntaxError for empty block tags
'basic-syntax28': ("{% %}", {}, template.TemplateSyntaxError),
### INHERITANCE TESTS #####################################################
# Standard template with no inheritance
'inheritance01': ("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}", {}, '1_3_'),
# Standard two-level inheritance
'inheritance02': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),
# Three-level with no redefinitions on third level
'inheritance03': ("{% extends 'inheritance02' %}", {}, '1234'),
# Two-level with no redefinitions on second level
'inheritance04': ("{% extends 'inheritance01' %}", {}, '1_3_'),
# Two-level with double quotes instead of single quotes
'inheritance05': ('{% extends "inheritance02" %}', {}, '1234'),
# Three-level with variable parent-template name
'inheritance06': ("{% extends foo %}", {'foo': 'inheritance02'}, '1234'),
# Two-level with one block defined, one block not defined
'inheritance07': ("{% extends 'inheritance01' %}{% block second %}5{% endblock %}", {}, '1_35'),
# Three-level with one block defined on this level, two blocks defined next level
'inheritance08': ("{% extends 'inheritance02' %}{% block second %}5{% endblock %}", {}, '1235'),
# Three-level with second and third levels blank
'inheritance09': ("{% extends 'inheritance04' %}", {}, '1_3_'),
# Three-level with space NOT in a block -- should be ignored
'inheritance10': ("{% extends 'inheritance04' %} ", {}, '1_3_'),
# Three-level with both blocks defined on this level, but none on second level
'inheritance11': ("{% extends 'inheritance04' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),
# Three-level with this level providing one and second level providing the other
'inheritance12': ("{% extends 'inheritance07' %}{% block first %}2{% endblock %}", {}, '1235'),
# Three-level with this level overriding second level
'inheritance13': ("{% extends 'inheritance02' %}{% block first %}a{% endblock %}{% block second %}b{% endblock %}", {}, '1a3b'),
# A block defined only in a child template shouldn't be displayed
'inheritance14': ("{% extends 'inheritance01' %}{% block newblock %}NO DISPLAY{% endblock %}", {}, '1_3_'),
# A block within another block
'inheritance15': ("{% extends 'inheritance01' %}{% block first %}2{% block inner %}inner{% endblock %}{% endblock %}", {}, '12inner3_'),
# A block within another block (level 2)
'inheritance16': ("{% extends 'inheritance15' %}{% block inner %}out{% endblock %}", {}, '12out3_'),
# {% load %} tag (parent -- setup for exception04)
'inheritance17': ("{% load testtags %}{% block first %}1234{% endblock %}", {}, '1234'),
# {% load %} tag (standard usage, without inheritance)
'inheritance18': ("{% load testtags %}{% echo this that theother %}5678", {}, 'this that theother5678'),
# {% load %} tag (within a child template)
'inheritance19': ("{% extends 'inheritance01' %}{% block first %}{% load testtags %}{% echo 400 %}5678{% endblock %}", {}, '140056783_'),
### EXCEPTION TESTS #######################################################
# Raise exception for invalid template name
'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError),
# Raise exception for invalid template name (in variable)
'exception02': ("{% extends nonexistent %}", {}, template.TemplateSyntaxError),
# Raise exception for extra {% extends %} tags
'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError),
# Raise exception for custom tags used in child with {% load %} tag in parent, not in child
'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError),
}
# This replaces the standard template_loader.
def test_template_loader(template_name, template_dirs=None):
try:
return TEMPLATE_TESTS[template_name][0]
except KeyError:
raise template.TemplateDoesNotExist, template_name
def run_tests(verbosity=0, standalone=False):
template_loader.load_template_source, old_template_loader = test_template_loader, template_loader.load_template_source
failed_tests = []
tests = TEMPLATE_TESTS.items()
tests.sort()
for name, vals in tests:
try:
output = template_loader.get_template(name).render(template.Context(vals[1]))
except Exception, e:
if e.__class__ == vals[2]:
if verbosity:
print "Template test: %s -- Passed" % name
else:
if verbosity:
print "Template test: %s -- FAILED. Got %s, exception: %s" % (name, e.__class__, e)
failed_tests.append(name)
continue
if output == vals[2]:
if verbosity:
print "Template test: %s -- Passed" % name
else:
if verbosity:
print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output)
failed_tests.append(name)
template_loader.load_template_source = old_template_loader
if failed_tests and not standalone:
msg = "Template tests %s failed." % failed_tests
if not verbosity:
msg += " Re-run tests with -v1 to see actual failures"
raise Exception, msg
if __name__ == "__main__":
run_tests(1, True)
......@@ -8,12 +8,13 @@ import os, sys, time, traceback
import doctest
APP_NAME = 'testapp'
OTHER_TESTS_DIR = "othertests"
TEST_DATABASE_NAME = 'django_test_db'
error_list = []
def log_error(model_name, title, description):
error_list.append({
'title': "%r model: %s" % (model_name, title),
'title': "%r module: %s" % (model_name, title),
'description': description,
})
......@@ -91,6 +92,7 @@ class TestRunner:
management.init()
# Run the tests for each test model.
self.output(1, "Running app tests")
for model_name in get_test_models():
self.output(1, "%s model: Importing" % model_name)
try:
......@@ -110,7 +112,32 @@ class TestRunner:
runner = DjangoDoctestRunner(verbosity_level=verbosity_level, verbose=False)
self.output(1, "%s model: Running tests" % model_name)
runner.run(dtest, clear_globs=True, out=sys.stdout.write)
# Run the non-model tests in the other tests dir
self.output(1, "Running other tests")
other_tests_dir = os.path.join(os.path.dirname(__file__), OTHER_TESTS_DIR)
test_modules = [f[:-3] for f in os.listdir(other_tests_dir) if f.endswith('.py') and not f.startswith('__init__')]
for module in test_modules:
self.output(1, "%s module: Importing" % module)
try:
mod = __import__("othertests." + module, '', '', [''])
except Exception, e:
log_error(module, "Error while importing", ''.join(traceback.format_exception(*sys.exc_info())[1:]))
continue
if mod.__doc__:
p = doctest.DocTestParser()
dtest = p.get_doctest(mod.__doc__, mod.__dict__, module, None, None)
runner = DjangoDoctestRunner(verbosity_level=verbosity_level, verbose=False)
self.output(1, "%s module: runing tests" % module)
runner.run(dtest, clear_globs=True, out=sys.stdout.write)
if hasattr(mod, "run_tests") and callable(mod.run_tests):
self.output(1, "%s module: runing tests" % module)
try:
mod.run_tests(verbosity_level)
except Exception, e:
log_error(module, "Exception running tests", ''.join(traceback.format_exception(*sys.exc_info())[1:]))
continue
# Unless we're using SQLite, remove the test database to clean up after
# ourselves. Connect to the previous database (not the test database)
# to do so, because it's not allowed to delete a database while being
......
# Custom tag library used in conjunction with template tests
from django.core import template
class EchoNode(template.Node):
def __init__(self, contents):
self.contents = contents
def render(self, context):
return " ".join(self.contents)
def do_echo(parser, token):
return EchoNode(token.contents.split()[1:])
template.register_tag("echo", do_echo)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment