From d23c3fe2e7b46eb4a4d53daf89ee54d422157436 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 30 Jun 2021 18:58:10 +0700 Subject: [PATCH 1/2] temp-commit --- bread/tests/helper.py | 36 ++++++++++++++++++++---------------- setup.py | 2 +- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/bread/tests/helper.py b/bread/tests/helper.py index 875a18c9..0ae4f40d 100644 --- a/bread/tests/helper.py +++ b/bread/tests/helper.py @@ -1,7 +1,8 @@ from collections import namedtuple -import mechanize from django.contrib.auth.models import User +from hypothesis import given +from hypothesis.extra.django import TestCase, from_model from bread.utils.urls import reverse_model @@ -17,16 +18,24 @@ def wrapper(case, *args, **kwargs): return wrapper -@authenticated -def generic_bread_test(case, model, **kwargs): - """Creates a single object, calls browse, read and edit pages""" - p = model(**kwargs) - p.save() - resp = case.client.get(reverse_model(model, "browse")) - case.assertEqual(resp.status_code, 200) - resp = case.client.get(reverse_model(model, "read", kwargs={"pk": p.pk})) - case.assertEqual(resp.status_code, 200) - test_form_page(case, reverse_model(model, "edit", kwargs={"pk": p.pk})) +def generic_bread_testcase(model, **kwargs): + class GenericModelTest(TestCase): + @given(from_model(model)) + def test_generic(self, instance): + print("did stuff") + assert instance.pk + resp = self.client.get(reverse_model(model, "browse")) + self.assertEqual(resp.status_code, 200) + resp = self.client.get( + reverse_model(model, "read", kwargs={"pk": instance.pk}) + ) + self.assertEqual(resp.status_code, 200) + resp = self.client.get( + reverse_model(model, "edit", kwargs={"pk": instance.pk}) + ) + self.assertEqual(resp.status_code, 200) + + return GenericModelTest def test_form_page(case, url, fuzzy_count=10): @@ -63,9 +72,4 @@ def test_form_page(case, url, fuzzy_count=10): def extract_form(url): - br = mechanize.Browser() - br.open(url) - form = br.select_form(name="") - print(form) - return [FormField(name="", value="", element="", generators=[])] diff --git a/setup.py b/setup.py index 06586907..5dad65c8 100644 --- a/setup.py +++ b/setup.py @@ -53,7 +53,7 @@ def readme(): "WeasyPrint", # creating PDFs "django-ckeditor", ], - extras_require={"testing": ["mechanize"]}, + extras_require={"testing": ["hypothesis[django]"]}, packages=find_packages(), setup_requires=["setuptools_scm"], zip_safe=False, From fd484ba850dcf0634f90678024c4fd297962c02a Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 6 Jul 2021 16:35:44 +0700 Subject: [PATCH 2/2] add: initial verson of generic hypothesis testing, see basxconnect package to see usage --- bread/tests/helper.py | 76 +++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 49 deletions(-) diff --git a/bread/tests/helper.py b/bread/tests/helper.py index 0ae4f40d..58fcf4f4 100644 --- a/bread/tests/helper.py +++ b/bread/tests/helper.py @@ -1,7 +1,8 @@ from collections import namedtuple from django.contrib.auth.models import User -from hypothesis import given +from django.test import Client +from hypothesis import given, settings from hypothesis.extra.django import TestCase, from_model from bread.utils.urls import reverse_model @@ -9,67 +10,44 @@ FormField = namedtuple("FormField", ["name", "value", "element", "generators"]) -def authenticated(func): - def wrapper(case, *args, **kwargs): - user, _ = User.objects.get_or_create(username="admin", is_superuser=True) - case.client.force_login(user) - return func(case, *args, **kwargs) - - return wrapper +def authenticate(client): + user, _ = User.objects.get_or_create(username="admin", is_superuser=True) + client.force_login(user) def generic_bread_testcase(model, **kwargs): class GenericModelTest(TestCase): + def setUp(self): + self.client = Client() + authenticate(self.client) + @given(from_model(model)) + @settings(deadline=None) def test_generic(self, instance): - print("did stuff") - assert instance.pk - resp = self.client.get(reverse_model(model, "browse")) + self.assertIsNotNone(instance.pk) + resp = self.client.get(reverse_model(model, "browse"), follow=True) self.assertEqual(resp.status_code, 200) resp = self.client.get( - reverse_model(model, "read", kwargs={"pk": instance.pk}) + reverse_model(model, "read", kwargs={"pk": instance.pk}), follow=True ) self.assertEqual(resp.status_code, 200) resp = self.client.get( - reverse_model(model, "edit", kwargs={"pk": instance.pk}) + reverse_model(model, "edit", kwargs={"pk": instance.pk}), follow=True + ) + resp = self.client.get( + reverse_model(model, "delete", kwargs={"pk": instance.pk}), follow=True ) self.assertEqual(resp.status_code, 200) - return GenericModelTest - - -def test_form_page(case, url, fuzzy_count=10): - - # find input-elements and create generators - # ignore hidden, readonly and unusable fields - # this function is likely the challenging part of the implementation - url = f"{case.live_server_url}{url}" - fields = extract_form(url) - - # save all fields unmodified and check save method works correctly - initial_fieldvalues = {i.name: i.value for i in extract_form(url)} - case.client.post(url, initial_fieldvalues) # post without changes - saved_fieldvalues = {i.name: i.value for i in extract_form(url)} - assert initial_fieldvalues == saved_fieldvalues - return - - # test mutations on all fields separately in a loop - # more performant would be to modify many fields inside a single request - # but it would less fine-grained and not reflect how most real-world edits happen - for field in fields: - # field.generators returns a list of tuples with a generator and a boolean is_valid_value - # generator is a python generator which returns an infinite number of random values for the field - # is_valid_value determines whether the generator generates valid values for the field or not - for generator, is_valid_value in field.generators: - for testvalue, _ in zip(generator, range(fuzzy_count)): - case.client.post(url, {**initial_fieldvalues, field.name: testvalue}) - updated_fields = case.client.get(url) - - if is_valid_value: - assert updated_fields[field.name] == testvalue - else: - assert updated_fields[field.name] == initial_fieldvalues[field.name] + def test_add(self): + resp = self.client.get(reverse_model(model, "add"), follow=True) + self.assertEqual(resp.status_code, 200) + # TODO: implement add form, use hypothesis + @given(from_model(model)) + @settings(deadline=None) + def test_forms(self, instance): + self.assertIsNotNone(instance.pk) + # TODO: implement edit form, use hypothesis -def extract_form(url): - return [FormField(name="", value="", element="", generators=[])] + return GenericModelTest