From d8391e54a5a5abb5b52f9d3c6867ddaefae92880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Fri, 1 Sep 2017 12:39:17 +0200 Subject: [PATCH] Add docs to kfet TestCases --- kfet/tests/testcases.py | 132 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 10 deletions(-) diff --git a/kfet/tests/testcases.py b/kfet/tests/testcases.py index 977345e7..e2fc09ff 100644 --- a/kfet/tests/testcases.py +++ b/kfet/tests/testcases.py @@ -10,7 +10,18 @@ from .utils import create_root, create_team, create_user class TestCaseMixin: + """Extends TestCase for kfet application tests.""" + 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 try: @@ -53,6 +64,18 @@ class TestCaseMixin: ) 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: self.assertEqual(response.status_code, 200) try: @@ -80,6 +103,10 @@ class TestCaseMixin: ) 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(): value = getattr(instance, attr) if callable(value): @@ -87,23 +114,104 @@ class TestCaseMixin: self.assertEqual(value, expected_value) 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: parsed = urlparse(actual) - checks = ['scheme', 'netloc', 'path', 'params'] - for check in checks: - self.assertEqual( - getattr(parsed, check), - expected.get(check, ''), - ) - self.assertDictEqual( - parse_qs(parsed.query), - expected.get('query', {}), - ) + for part, expected_part in expected.items(): + if part == 'query': + self.assertDictEqual( + parse_qs(parsed.query), + expected.get('query', {}), + ) + else: + self.assertEqual(getattr(parsed, part), expected_part) else: self.assertEqual(actual, expected) 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 '_data'. + + """ url_name = None url_expected = None @@ -113,6 +221,9 @@ class ViewTestCaseMixin(TestCaseMixin): auth_forbidden = [] def setUp(self): + """ + Warning: Do not forget to call super().setUp() in subclasses. + """ # Signals handlers on login/logout send messages. # Due to the way the Django' test Client performs login, this raise an # error. As workaround, we mock the Django' messages module. @@ -125,6 +236,7 @@ class ViewTestCaseMixin(TestCaseMixin): # 'auto_now_add' fields. self.now = timezone.now() + # These attributes register users and accounts instances. self.users = {} self.accounts = {}