UPD: dav_base: tests!

This commit is contained in:
2019-03-12 18:13:19 +01:00
parent c38cc0d6e5
commit b246a785b7
11 changed files with 432 additions and 45 deletions

2
.gitignore vendored
View File

@@ -1,8 +1,10 @@
*.pyc
*.mo
geckodriver.log
.idea/
django_dav_events.egg-info/
backup/
env/
test-screenshots/

View File

@@ -4,3 +4,7 @@
EMAIL_SENDER = 'DAV heinzel <heinzel@alpenverein-karlsruhe.de>'
EMAIL_BASE_URL = 'http://localhost:8000'
EMAIL_SUBJECT_PREFIX = u'[DAV heinzel]'
# The following settings are for the test suite. Do not change them.
TEST_SETTING = 'do not change this value'
# NO_TEST_SETTING = 'do not set this'

View File

@@ -48,7 +48,7 @@ class AbstractMail(object):
def _get_reply_to(self):
return None
def send(self):
def send(self, fail_silently=False):
subject = self._get_subject()
body = self._get_body()
sender = self._get_sender()
@@ -56,5 +56,8 @@ class AbstractMail(object):
reply_to = self._get_reply_to()
email = EmailMessage(subject=subject, body=body, from_email=sender, to=recipients, reply_to=reply_to)
logger.info(u'Send %s to %s', self.__class__.__name__, recipients)
email.send()
if fail_silently:
logger.info(u'Fake sending %s to %s', self.__class__.__name__, recipients)
else:
logger.info(u'Send %s to %s', self.__class__.__name__, recipients)
email.send(fail_silently=fail_silently)

180
dav_base/tests/generic.py Normal file
View File

@@ -0,0 +1,180 @@
import datetime
import os
import sys
import urllib
from unittest import skip
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.test import SimpleTestCase, TestCase, tag
from django.urls import reverse
from selenium import webdriver
def skip_unless_tag_option():
if '--tag' in sys.argv:
return lambda func: func
else:
return skip('Skipped unless --tag option is used')
class Url(object):
def __init__(self, location, name=None, func=None, **kwargs):
self.location = location
self.name = name
self.func = func
self.redirect = kwargs.get('redirect', False)
self.status_code = kwargs.get('status_code', 200)
self.follow = kwargs.get('follow', False)
class UrlsTestCase(SimpleTestCase):
urls = ()
def test_locations(self):
for url in self.urls:
if url.location:
response = self.client.get(url.location, follow=url.follow)
if url.redirect:
self.assertRedirects(response, url.redirect)
else:
self.assertEqual(response.status_code, url.status_code,
'Getting \'{}\' is not OK'.format(url.location))
if url.func:
self.assertEqual(response.resolver_match.func.__name__,
url.func.__name__,
'Getting \'{}\' resolve to wrong function'.format(url.location))
def test_names(self):
for url in self.urls:
if url.name:
response = self.client.get(reverse(url.name), follow=url.follow)
if url.redirect:
self.assertRedirects(response, url.redirect)
else:
self.assertEqual(response.status_code, url.status_code,
'Getting url named \'{}\' is not OK'.format(url.name))
if url.func:
self.assertEqual(response.resolver_match.func.__name__,
url.func.__name__,
'Getting url named \'{}\' resolve to wrong function'.format(url.name))
class FormDataSet(object):
def __init__(self, data, expected_errors=None, form_kwargs=None):
self.data = data
self.expected_errors = expected_errors
self.form_kwargs = form_kwargs
class FormsTestCase(TestCase):
form_class = None
valid_data_sets = ()
invalid_data_sets = ()
def test_valid_data(self, form_class=None, data_sets=None, form_kwargs=None):
if form_class is None:
form_class = self.form_class
if form_class is None:
return True
if data_sets is None:
data_sets = self.valid_data_sets
for data_set in data_sets:
fk = {}
if form_kwargs is not None:
fk.update(form_kwargs)
if data_set.form_kwargs is not None:
fk.update(data_set.form_kwargs)
fk['data'] = data_set.data
form = form_class(**fk)
if not form.is_valid():
errors = []
for key in form.errors.as_data():
for ve in form.errors[key].as_data():
errors.append(u'%s (%s)' % (ve.code, ve.message))
self.fail(u'Invalid form data \'%s\': %s' % (data_set.data, errors))
def test_invalid_data(self, form_class=None, data_sets=None, form_kwargs=None):
if form_class is None:
form_class = self.form_class
if form_class is None:
return True
if data_sets is None:
data_sets = self.invalid_data_sets
for data_set in data_sets:
fk = {}
if form_kwargs is not None:
fk.update(form_kwargs)
if data_set.form_kwargs is not None:
fk.update(data_set.form_kwargs)
fk['data'] = data_set.data
form = form_class(**fk)
if form.is_valid():
self.fail('Valid form data: \'%s\'' % data_set.data)
if data_set.expected_errors:
error_dicts = form.errors.as_data()
for key, code in data_set.expected_errors:
error_codes = [ve.code for ve in error_dicts[key]]
self.assertIn(code, error_codes)
class ScreenshotTestCase(StaticLiveServerTestCase):
locations = ()
@classmethod
def setUpClass(cls):
super(ScreenshotTestCase, cls).setUpClass()
# screenshot_base_dir = os.path.join('/', 'tmp', 'test-screenshots')
screenshot_base_dir = 'test-screenshots'
cls.screenshot_path = screenshot_base_dir
def setUp(self):
super(ScreenshotTestCase, self).setUp()
self.selenium = webdriver.Firefox()
self.selenium.set_window_size(1024, 768)
def tearDown(self):
self.selenium.quit()
super(ScreenshotTestCase, self).tearDown()
def complete_url(self, location):
return '{}/{}'.format(self.live_server_url, location.lstrip('/'))
def sanitize_filename(self, location):
location = location.lstrip('/')
if location == '':
return 'root'
r = urllib.quote(location, '')
return r
def save_screenshot(self, name=None):
if self.screenshot_path:
if name is None:
location = self.selenium.current_url
if location.startswith(self.live_server_url):
location = location[len(self.live_server_url):]
name = location
now = datetime.datetime.now()
base_name = '{timestamp}-{name}.png'.format(name=self.sanitize_filename(name),
timestamp=now.strftime('%Y%m%d-%H%M%S'))
path = os.path.join(self.screenshot_path, base_name)
if not os.path.isdir(self.screenshot_path):
os.makedirs(self.screenshot_path, 0700)
self.selenium.save_screenshot(path)
@skip_unless_tag_option()
@tag('screenshots')
def test_screenshots(self):
for location in self.locations:
self.selenium.get(self.complete_url(location))
self.save_screenshot()

View File

@@ -1,8 +1,8 @@
from django.apps import apps
from django.test import TestCase
from django.test import SimpleTestCase
class AppsTestCase(TestCase):
class AppsTestCase(SimpleTestCase):
def setUp(self):
app_config = apps.get_containing_app_config(__package__)
self.settings = app_config.settings

View File

@@ -0,0 +1,154 @@
# -*- coding: utf-8 -*-
from django.apps import apps
from django.core.exceptions import ImproperlyConfigured
from django.test import SimpleTestCase
from ..config.apps import DefaultSetting, AppSettings, AppConfig
from ..apps import AppConfig as RealAppConfig
TEST_SETTING_VALUE = 'do not change this value'
class DefaultSettingTestCase(SimpleTestCase):
def test_key_name(self):
name = 'somename'
key_name = 'SoMeKeY'
setting = DefaultSetting(name, None)
self.assertEqual(setting.key_name, name.upper())
setting = DefaultSetting(name, None, key_name=key_name)
self.assertEqual(setting.key_name, key_name)
def test_validate(self):
name = 'somename'
setting = DefaultSetting(name, None, validator=None)
try:
setting.validate(False)
except ImproperlyConfigured:
self.fail('Disabled validation validated invalid :(')
def callable_validator(value):
return (value % 2) == 0
valid_values = (2, 4)
invalid_values = (3, 5)
setting = DefaultSetting(name, None, validator=callable_validator)
for val in valid_values:
try:
setting.validate(val)
except ImproperlyConfigured:
self.fail('Callable validated valid value invalid :(')
for val in invalid_values:
with self.assertRaises(ImproperlyConfigured):
setting.validate(val)
re_validator = r'[a-z]'
valid_values = u'aocd'
invalid_values = u'Aö1.'
setting = DefaultSetting(name, None, validator=re_validator)
for val in valid_values:
try:
setting.validate(val)
except ImproperlyConfigured:
self.fail('Regular Expression validated valid value invalid :(')
for val in invalid_values:
with self.assertRaises(ImproperlyConfigured):
setting.validate(val)
class AppSettingsTestCase(SimpleTestCase):
def setUp(self):
self.app_name = 'dav_base'
self.test_setting_value = TEST_SETTING_VALUE
def test_defaults(self):
"""Test the default value for optional and unset settings"""
default_settings = (
DefaultSetting('no_test_setting', 1),
DefaultSetting('no_test_setting_2', 2),
)
app_settings = AppSettings(self.app_name, default_settings)
self.assertEqual(app_settings.no_test_setting, 1)
self.assertEqual(app_settings.no_test_setting_2, 2)
def test_improperlyconfigured(self):
"""Test if mandatory but unset setting raise correct exception"""
default_settings = (
DefaultSetting('no_test_setting', ImproperlyConfigured),
)
try:
app_settings = AppSettings(self.app_name, default_settings)
except ImproperlyConfigured as e:
self.assertEqual(str(e), 'NO_TEST_SETTING must be defined in main.settings-dav_base')
def test_settings_from_file(self):
"""Test if value from settings file eliminate exception"""
default_settings = (
DefaultSetting('test_setting', ImproperlyConfigured),
)
app_settings = AppSettings(self.app_name, default_settings)
self.assertEqual(app_settings.test_setting, self.test_setting_value)
# Test if value from settings file overwrites default value
default_settings = (
DefaultSetting('test_setting', 1),
)
app_settings = AppSettings(self.app_name, default_settings)
self.assertEqual(app_settings.test_setting, self.test_setting_value)
def test_key_name(self):
default_settings = (
DefaultSetting('test_setting', 1, key_name='NO_TEST_SETTING'),
DefaultSetting('no_test_setting', ImproperlyConfigured, key_name='TEST_SETTING'),
)
app_settings = AppSettings(self.app_name, default_settings)
self.assertEqual(app_settings.test_setting, 1)
self.assertEqual(app_settings.no_test_setting, self.test_setting_value)
class AppConfigTestCase(SimpleTestCase):
def test_init(self):
app_name = 'dav_base'
import dav_base as app_module
test_default_settings = (
DefaultSetting('test_setting', ImproperlyConfigured),
DefaultSetting('no_test_setting', 1),
)
class TestAppConfig(AppConfig):
name = 'not_dav_base'
verbose_name = u'DAV Base App'
default_settings = test_default_settings
app_config = TestAppConfig(app_name, app_module)
app_settings = app_config.settings
self.assertEqual(app_config.name, app_name)
self.assertEqual(app_settings.test_setting, TEST_SETTING_VALUE)
self.assertEqual(app_settings.no_test_setting, 1)
def test_integrated(self):
app_config = apps.get_containing_app_config(__package__)
self.assertEqual(app_config.__class__, RealAppConfig)
self.assertIsInstance(app_config, AppConfig)
self.assertEqual(app_config.settings.__class__, AppSettings)
class ModuleMetaTestCase(SimpleTestCase):
def test_some(self):
# TODO
pass
class ModuleConfigTestCase(SimpleTestCase):
def test_some(self):
# TODO
pass

View File

@@ -1,20 +1,20 @@
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
from django.test import SimpleTestCase
from ..emails import AbstractMail
class EmailsTestCase(TestCase):
class EmailsTestCase(SimpleTestCase):
def setUp(self):
self.email = AbstractMail()
def test_send(self):
try:
self.email.send()
self.assertTrue(False, 'AbstractEmail.send() does not raise an Exception')
self.fail('AbstractEmail.send() does not raise an Exception')
except NotImplementedError:
pass
except ImproperlyConfigured:
pass
except Exception:
self.assertTrue(False, 'AbstractEmail.send() raised unexpected Exception')
self.fail('AbstractEmail.send() raised unexpected Exception')

View File

@@ -0,0 +1,8 @@
from .generic import ScreenshotTestCase
class TestCase(ScreenshotTestCase):
locations = (
'/',
'404',
)

View File

@@ -0,0 +1,48 @@
from django.test import SimpleTestCase
class TemplatesTestCase(SimpleTestCase):
def setUp(self):
super(TemplatesTestCase, self).setUp()
self.response_from_root_view = self.client.get('/')
def test_template_usage(self):
response = self.response_from_root_view
self.assertTemplateUsed(response, 'dav_base/base.html')
self.assertTemplateUsed(response, 'project_name.html')
def test_html_head(self):
response = self.response_from_root_view
html_needles = (
# favicon
'<link type="image/x-icon" href="/static/dav_base/img/dav-favicon.ico" rel="shortcut icon" />',
# bootstrap css
'<link type="text/css" href="/static/dav_base/bootstrap/css/bootstrap.min.css" rel="stylesheet" />',
# css file for jquery.dataTables.js
'<link type="text/css" href="/static/dav_base/css/dataTables.bootstrap.min.css" rel="stylesheet" />',
# local css file
'<link type="text/css" href="/static/dav_base/css/local.css" rel="stylesheet" />',
# jquery.js file
'<script type="text/javascript" src="/static/dav_base/js/jquery.min.js"></script>',
# jquery.dataTables.js file
'<script type="text/javascript" src="/static/dav_base/js/jquery.dataTables.min.js"></script>',
# bootstrap js file
'<script type="text/javascript" src="/static/dav_base/bootstrap/js/bootstrap.min.js"></script>',
)
for needle in html_needles:
self.assertInHTML(needle, response.content)
def test_page_footer(self):
response = self.response_from_root_view
html = """
<div id="page-footer">
<div class="signum"><a href="mailto:heinzel@alpenverein-karlsruhe.de">heinzel@alpenverein-karlsruhe.de</a></div>
<a href="http://alpenverein-karlsruhe.de" target="_blank">&copy; Sektion Karlsruhe im Deutschen Alpenverein (DAV) e.V.</a> &ensp;&bull;&ensp;
<a href="http://alpenverein-karlsruhe.de/impressum">Impressum</a>
</div>
"""
self.assertInHTML(html, response.content)

View File

@@ -1,33 +1,9 @@
from django.test import TestCase, Client
from django.urls import reverse
from generic import Url, UrlsTestCase
from ..views import RootView
class UrlsTestCase(TestCase):
def setUp(self):
self.client = Client()
def test_root(self):
url = '/'
response = self.client.get(url, follow=False)
self.assertEqual(response.status_code, 200,
'Getting {} is not OK'.format(url))
self.assertEqual(response.resolver_match.func.__name__,
RootView.as_view().__name__,
'Getting {} resolve to wrong view'.format(url))
def test_root_by_name(self):
name = 'root'
response = self.client.get(reverse(name), follow=False)
self.assertEqual(response.status_code, 200,
'Getting url named \'{}\' is not OK'.format(name))
self.assertEqual(response.resolver_match.func.__name__,
RootView.as_view().__name__,
'Getting url named \'{}\' resolve to wrong view'.format(name))
def test_djangoadmin(self):
url = '/djangoadmin'
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200,
'Getting {} is not OK'.format(url))
class TestCase(UrlsTestCase):
urls = (
Url('/', 'root', RootView.as_view()),
Url('/djangoadmin', follow=True),
)

View File

@@ -1,10 +1,22 @@
from django.test import TestCase, Client
from django.test import SimpleTestCase
from ..views import RootView
class ViewsTestCase(TestCase):
def setUp(self):
self.client = Client()
class ViewsTestCase(SimpleTestCase):
def test_root(self):
response = self.client.get('/', follow=False)
view = RootView()
template_names = view.get_template_names()
self.assertEqual(len(template_names), 1)
self.assertIn('dav_base/root.html', template_names)
context = view.get_context_data()
self.assertIn('root_urls', context)
def test_integrated_root(self):
response = self.client.get('/')
self.assertTemplateUsed(response, 'dav_base/root.html')
self.assertIn('root_urls', response.context, '\'root_urls\' not in context of root view')
# TODO
# Maybe we should set a defined module config, so we could
# test the content of the root_urls context variable.