From e5cea49673c2f528b6fb94d8f42c2f4b64a36f4c Mon Sep 17 00:00:00 2001 From: Oliver Zander Date: Mon, 18 Aug 2025 16:42:09 +0200 Subject: [PATCH] added basic tests for extern view --- input/tests/__init__.py | 3 ++ input/tests/views.py | 40 ++++++++++++++ input/utils/__init__.py | 0 input/utils/testing.py | 114 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 input/tests/views.py create mode 100644 input/utils/__init__.py create mode 100644 input/utils/testing.py diff --git a/input/tests/__init__.py b/input/tests/__init__.py index 14a304a..cb7cb1b 100755 --- a/input/tests/__init__.py +++ b/input/tests/__init__.py @@ -8,6 +8,9 @@ from django.http import HttpResponse from input.forms import LibraryForm from input.models import HonoraryCertificate, Project, Account, Literature +from .views import ViewTestCase + + class TestWithoutLogin(TestCase): def setUp(self): diff --git a/input/tests/views.py b/input/tests/views.py new file mode 100644 index 0000000..89835f5 --- /dev/null +++ b/input/tests/views.py @@ -0,0 +1,40 @@ +from django.test import TestCase + +from input.utils.testing import request + + +class ViewTestCase(TestCase): + + def test_index(self): + request(self, 'index') + + def test_extern(self): + request(self, 'extern') + + def test_extern_travel(self): + data = { + 'extern_view-current_step': 0, + '0-realname': 'Test', + '0-email': 'test@example.com', + '0-choice': 'TRAV', + '0-check': True, + } + + response = request(self, 'extern', data=data) + + self.assertContains(response, 'Transportmittel') + + data = { + 'extern_view-current_step': 1, + 'project_name': 'Test', + 'transport': 'BAHN', + 'travelcost': 10, + 'checkin': '2025-01-01', + 'checkout': '2025-01-02', + 'hotel': 'TRUE', + 'notes': '', + } + + response = request(self, 'extern', data=data) + + self.assertContains(response, 'Deine Anfrage wurde gesendet.') diff --git a/input/utils/__init__.py b/input/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/input/utils/testing.py b/input/utils/testing.py new file mode 100644 index 0000000..2481df7 --- /dev/null +++ b/input/utils/testing.py @@ -0,0 +1,114 @@ +from typing import Any, Iterable, Mapping, Union, Tuple, Protocol + +from django.http import HttpRequest, HttpResponse +from django.http.response import HttpResponseRedirectBase, StreamingHttpResponse +from django.shortcuts import resolve_url +from django.template import Context +from django.template.response import TemplateResponse +from django.test import Client, SimpleTestCase +from django.urls import reverse, ResolverMatch +from django.utils.http import urlencode + +FormData = dict +JSONDict = dict +JSONList = list +RequestData = Union[FormData, JSONDict, JSONList] +QueryParams = Union[Mapping[str, Any], Iterable[Tuple[str, Any]]] + + +class TestClientResponse(Protocol): + client: Client + request: HttpRequest + templates: list + context: Context + resolver_match: ResolverMatch + + def json(self) -> Union[JSONList, JSONDict]: ... + + +Response = Union[ + HttpResponse, + HttpResponseRedirectBase, + StreamingHttpResponse, + TemplateResponse, + TestClientResponse, +] + + +class ObjectWithGetAbsoluteURLMethod(Protocol): + + def get_absolute_url(self) -> str: ... + + +URL = Union[str, ObjectWithGetAbsoluteURLMethod] +URLArgs = Union[tuple, list] +URLKwargs = dict + + +def get_url(url: URL, args: URLArgs = None, kwargs: URLKwargs = None) -> str: + """ + Helper to reverse the given url name. + """ + + if args or kwargs: + return reverse(url, args=args, kwargs=kwargs) + + return resolve_url(url) + + +def get_handler(test_case: SimpleTestCase, method: str = None, data=None): + if data: + method = str.lower(method or 'POST') + else: + method = str.lower(method or 'GET') + + return getattr(test_case.client, method) + + +def request( + test_case: SimpleTestCase, + url: URL, + status_code: int = None, + expected_url: URL = None, + args: URLArgs = None, + kwargs: URLKwargs = None, + headers: dict = None, + msg: str = None, + query_params: QueryParams = None, + method: str = None, + data: RequestData = None, + **options, +) -> Response: + """ + A helper to make a request with the test case's http client. + + The given args and kwargs are used to reverse the url + but not the expected url. When expected url needs + args/kwargs pass an absolute url instead. + + All additional kwargs are passed as post parameters. + When posting without parameters just pass post=True. + """ + + data = data or options or None + handler = get_handler(test_case, method, data) + url = get_url(url, args, kwargs) + + if query_params: + url = f'{url}?%s' % urlencode(query_params, doseq=True) + + headers = headers or {} + status_code = status_code or 200 + response = handler(url, data=data, **headers) + msg = msg or getattr(response, 'content', None) + + if expected_url: + test_case.assertRedirects( + response=response, + expected_url=get_url(expected_url), + target_status_code=status_code, + ) + else: + test_case.assertEqual(response.status_code, status_code, msg=msg) + + return response