forked from DGNum/gestioCOF
Add docs to kfet TestCases
This commit is contained in:
parent
0afbd577b1
commit
d8391e54a5
1 changed files with 122 additions and 10 deletions
|
@ -10,7 +10,18 @@ from .utils import create_root, create_team, create_user
|
||||||
|
|
||||||
|
|
||||||
class TestCaseMixin:
|
class TestCaseMixin:
|
||||||
|
"""Extends TestCase for kfet application tests."""
|
||||||
|
|
||||||
def assertForbidden(self, response):
|
def assertForbidden(self, response):
|
||||||
|
"""
|
||||||
|
Test that the response (retrieved with a Client) is a denial of access.
|
||||||
|
|
||||||
|
The response should verify one of the following:
|
||||||
|
- its HTTP response code is 403,
|
||||||
|
- it redirects to the login page with a GET parameter named 'next'
|
||||||
|
whose value is the url of the requested page.
|
||||||
|
|
||||||
|
"""
|
||||||
request = response.wsgi_request
|
request = response.wsgi_request
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -53,6 +64,18 @@ class TestCaseMixin:
|
||||||
)
|
)
|
||||||
|
|
||||||
def assertForbiddenKfet(self, response, form_ctx='form'):
|
def assertForbiddenKfet(self, response, form_ctx='form'):
|
||||||
|
"""
|
||||||
|
Test that a response (retrieved with a Client) contains error due to
|
||||||
|
lack of kfet permissions.
|
||||||
|
|
||||||
|
It checks that 'Permission refusée' is present in the non-field errors
|
||||||
|
of the form of response context at key 'form_ctx', or present in
|
||||||
|
messages.
|
||||||
|
|
||||||
|
This should be used for pages which can be accessed by the kfet team
|
||||||
|
members, but require additionnal permission(s) to make an operation.
|
||||||
|
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
try:
|
try:
|
||||||
|
@ -80,6 +103,10 @@ class TestCaseMixin:
|
||||||
)
|
)
|
||||||
|
|
||||||
def assertInstanceExpected(self, instance, expected):
|
def assertInstanceExpected(self, instance, expected):
|
||||||
|
"""
|
||||||
|
Test that the values of the attributes and without-argument methods of
|
||||||
|
'instance' are equal to 'expected' pairs.
|
||||||
|
"""
|
||||||
for attr, expected_value in expected.items():
|
for attr, expected_value in expected.items():
|
||||||
value = getattr(instance, attr)
|
value = getattr(instance, attr)
|
||||||
if callable(value):
|
if callable(value):
|
||||||
|
@ -87,23 +114,104 @@ class TestCaseMixin:
|
||||||
self.assertEqual(value, expected_value)
|
self.assertEqual(value, expected_value)
|
||||||
|
|
||||||
def assertUrlsEqual(self, actual, expected):
|
def assertUrlsEqual(self, actual, expected):
|
||||||
|
"""
|
||||||
|
Test that the url 'actual' is as 'expected'.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
actual (str): Url to verify.
|
||||||
|
expected: Two forms are accepted.
|
||||||
|
* (str): Expected url. Strings equality is checked.
|
||||||
|
* (dict): Its keys must be attributes of 'urlparse(actual)'.
|
||||||
|
Equality is checked for each present key, except for
|
||||||
|
'query' which must be a dict of the expected query string
|
||||||
|
parameters.
|
||||||
|
|
||||||
|
"""
|
||||||
if type(expected) == dict:
|
if type(expected) == dict:
|
||||||
parsed = urlparse(actual)
|
parsed = urlparse(actual)
|
||||||
checks = ['scheme', 'netloc', 'path', 'params']
|
for part, expected_part in expected.items():
|
||||||
for check in checks:
|
if part == 'query':
|
||||||
self.assertEqual(
|
|
||||||
getattr(parsed, check),
|
|
||||||
expected.get(check, ''),
|
|
||||||
)
|
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
parse_qs(parsed.query),
|
parse_qs(parsed.query),
|
||||||
expected.get('query', {}),
|
expected.get('query', {}),
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
self.assertEqual(getattr(parsed, part), expected_part)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(actual, expected)
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
|
||||||
class ViewTestCaseMixin(TestCaseMixin):
|
class ViewTestCaseMixin(TestCaseMixin):
|
||||||
|
"""
|
||||||
|
TestCase extension to ease tests of kfet views.
|
||||||
|
|
||||||
|
|
||||||
|
Urls concerns
|
||||||
|
-------------
|
||||||
|
|
||||||
|
# Basic usage
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
url_name (str): Name of view under test, as given to 'reverse'
|
||||||
|
function.
|
||||||
|
url_args (list, optional): Will be given to 'reverse' call.
|
||||||
|
url_kwargs (dict, optional): Same.
|
||||||
|
url_expcted (str): What 'reverse' should return given previous
|
||||||
|
attributes.
|
||||||
|
|
||||||
|
View url can then be accessed at the 'url' attribute.
|
||||||
|
|
||||||
|
# Advanced usage
|
||||||
|
|
||||||
|
If multiple combinations of url name, args, kwargs can be used for a view,
|
||||||
|
it is possible to define 'urls_conf' attribute. It must be a list whose
|
||||||
|
each item is a dict defining arguments for 'reverse' call ('name', 'args',
|
||||||
|
'kwargs' keys) and its expected result ('expected' key).
|
||||||
|
|
||||||
|
The reversed urls can be accessed at the 't_urls' attribute.
|
||||||
|
|
||||||
|
|
||||||
|
Users concerns
|
||||||
|
--------------
|
||||||
|
|
||||||
|
During setup, three users are created with their kfet account:
|
||||||
|
- 'user': a basic user without any permission, account trigramme: 000,
|
||||||
|
- 'team': a user with kfet.is_team permission, account trigramme: 100,
|
||||||
|
- 'root': a superuser, account trigramme: 200.
|
||||||
|
Their password is their username.
|
||||||
|
|
||||||
|
One can create additionnal users with 'users_extra' attribute, or prevent
|
||||||
|
these 3 users to be created with 'users_base' attribute. See these two
|
||||||
|
properties for further informations.
|
||||||
|
|
||||||
|
By using 'register_user' method, these users can then be accessed at
|
||||||
|
'users' attribute by their label. Similarly, their kfet account is
|
||||||
|
registered on 'accounts' attribute.
|
||||||
|
|
||||||
|
A user label can be given to 'auth_user' attribute. The related user is
|
||||||
|
then authenticated on self.client during test setup. Its value defaults to
|
||||||
|
'None', meaning no user is authenticated.
|
||||||
|
|
||||||
|
|
||||||
|
Automated tests
|
||||||
|
---------------
|
||||||
|
|
||||||
|
# Url reverse
|
||||||
|
|
||||||
|
Based on url-related attributes/properties, the test 'test_urls' checks
|
||||||
|
that expected url is returned by 'reverse' (once with basic url usage and
|
||||||
|
each for advanced usage).
|
||||||
|
|
||||||
|
# Forbidden responses
|
||||||
|
|
||||||
|
The 'test_forbidden' test verifies that each user, from labels of
|
||||||
|
'auth_forbidden' attribute, can't access the url(s), i.e. response should
|
||||||
|
be a 403, or a redirect to login view.
|
||||||
|
|
||||||
|
Tested HTTP requests are given by 'http_methods' attribute. Additional data
|
||||||
|
can be given by defining an attribute '<method(lowercase)>_data'.
|
||||||
|
|
||||||
|
"""
|
||||||
url_name = None
|
url_name = None
|
||||||
url_expected = None
|
url_expected = None
|
||||||
|
|
||||||
|
@ -113,6 +221,9 @@ class ViewTestCaseMixin(TestCaseMixin):
|
||||||
auth_forbidden = []
|
auth_forbidden = []
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Warning: Do not forget to call super().setUp() in subclasses.
|
||||||
|
"""
|
||||||
# Signals handlers on login/logout send messages.
|
# Signals handlers on login/logout send messages.
|
||||||
# Due to the way the Django' test Client performs login, this raise an
|
# Due to the way the Django' test Client performs login, this raise an
|
||||||
# error. As workaround, we mock the Django' messages module.
|
# error. As workaround, we mock the Django' messages module.
|
||||||
|
@ -125,6 +236,7 @@ class ViewTestCaseMixin(TestCaseMixin):
|
||||||
# 'auto_now_add' fields.
|
# 'auto_now_add' fields.
|
||||||
self.now = timezone.now()
|
self.now = timezone.now()
|
||||||
|
|
||||||
|
# These attributes register users and accounts instances.
|
||||||
self.users = {}
|
self.users = {}
|
||||||
self.accounts = {}
|
self.accounts = {}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue