diff --git a/HISTORY.rst b/HISTORY.rst index 07accba..653271e 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -5,7 +5,10 @@ History Next Release ------------ -- Nothing yet! +- Add UserFactory to make testing easier for developers using the + pacakge; requires factory_boy (PR `#20`_) + +.. _#20: https://github.com/jambonsw/django-improved-user/pull/20 0.3.0 (2017-08-10) ------------------ diff --git a/README.rst b/README.rst index 5f2b322..6d1f788 100644 --- a/README.rst +++ b/README.rst @@ -8,6 +8,28 @@ default by making a few modern and international changes. * Replace ``first_name`` and ``last_name`` with international friendly ``short_name`` ``full name`` fields +Installation +------------ + +In a Terminal, use `pip` to install the package from +[PyPI](https://pypi.org/). + +.. code:: console + + pip install django-improved-user + +If you intend to use the `UserFactory` provided by the package to allow +for testing with [factory_boy](https://github.com/FactoryBoy/factory_boy), +you can specify so during install. + +.. code:: console + + pip install django-improved-user[factory] + +If you do not but wish to use the `UserFactory`, you will need to +install [factory_boy](https://github.com/FactoryBoy/factory_boy) +yourself. + Usage ----- @@ -40,8 +62,27 @@ Perform the following steps in your ``settings.py`` file. Testing ------- -From the root directory of the project, run the code below. +To run the test suite on a single version of Django (assuming you have a +version of Django installed), run the `runtests.py` script from the root +of the project. .. code:: console $ python runtests.py + +You can limit the tests or pass paramaters as if you had called +`manage.py test`. + +.. code:: console + + $ ./runtests.py tests.test_basic -v 3 + +To run all linters and test multiple Python and Django versions, use +`tox`. + +.. code:: console + + $ tox + +You will need to install Python 3.4, 3.5, and 3.6 on your system for +this to work. diff --git a/requirements.txt b/requirements.txt index 9c50cb9..a525c24 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,7 @@ bumpversion==0.5.3 +factory_boy==2.9.2 +Faker==0.7.18 +python-dateutil==2.6.1 check-manifest==0.35 coverage==4.4.1 docutils==0.14 diff --git a/setup.py b/setup.py index 3c58444..e02fe85 100755 --- a/setup.py +++ b/setup.py @@ -143,6 +143,13 @@ def run_tests(self): install_requires=[ 'django>=1.8', ], + extras_require={ + 'factory': [ + 'factory_boy==2.9.2', + 'Faker==0.7.18', + 'python-dateutil==2.6.1', + ], + }, zip_safe=False, cmdclass={ diff --git a/src/improved_user/factories.py b/src/improved_user/factories.py new file mode 100644 index 0000000..44dd6bd --- /dev/null +++ b/src/improved_user/factories.py @@ -0,0 +1,27 @@ +"""Factories to make testing with Improved User easier""" +from .models import User + +try: + from factory import Faker, PostGenerationMethodCall + from factory.django import DjangoModelFactory +except (ImportError, ModuleNotFoundError): # pragma: no cover + raise Exception( + "Please install factory_boy to use Improved User's UserFactory.\n" + 'pip install factory_boy==2.9.2') + + +# pylint: disable=too-few-public-methods +class UserFactory(DjangoModelFactory): + """Factory Boy factory for Improved User""" + class Meta: + """Configuration Options""" + model = User + + email = Faker('email') + password = PostGenerationMethodCall('set_password', 'password!') + full_name = Faker('name') + short_name = Faker('first_name') + is_active = True + is_staff = False + is_superuser = False +# pylint: enable=too-few-public-methods diff --git a/tests/test_factories.py b/tests/test_factories.py new file mode 100644 index 0000000..fd8d822 --- /dev/null +++ b/tests/test_factories.py @@ -0,0 +1,71 @@ +"""Test model factories provided by Improved User""" +from django.test import TestCase + +from improved_user.factories import UserFactory +from improved_user.models import User + + +class UserFactoryTests(TestCase): + """Test for UserFactory used with Factory Boy""" + + def test_basic_build(self): + """Test creation of User via factory""" + user = UserFactory.build() + self.assertIsInstance(user, User) + self.assertIsInstance(user.email, str) + self.assertIsInstance(user.short_name, str) + self.assertIsInstance(user.full_name, str) + self.assertGreater(len(user.email), 1) + self.assertGreater(len(user.short_name), 1) + self.assertGreater(len(user.full_name), 1) + self.assertTrue(user.check_password('password!')) + self.assertTrue(user.is_active) + self.assertFalse(user.is_staff) + self.assertFalse(user.is_superuser) + self.assertEqual(User.objects.all().count(), 0) + user.save() + self.assertEqual(User.objects.all().count(), 1) + + def test_basic_create(self): + """Test creation of User via factory saves to DB""" + user = UserFactory() + self.assertIsInstance(user, User) + self.assertEqual(User.objects.all().count(), 1) + + def test_attributes_override_build(self): + """Test that all model fields can be modified""" + user = UserFactory.build( + email='hello@jambonsw.com', + password='my_secret_password87', + short_name='René', + full_name='René Magritte', + is_active=False, + is_staff=True, + is_superuser=True, + ) + self.assertIsInstance(user, User) + self.assertEqual(user.email, 'hello@jambonsw.com') + self.assertEqual(user.short_name, 'René') + self.assertEqual(user.full_name, 'René Magritte') + self.assertTrue(user.check_password('my_secret_password87')) + self.assertFalse(user.is_active) + self.assertTrue(user.is_staff) + self.assertTrue(user.is_superuser) + self.assertEqual(User.objects.all().count(), 0) + user.save() + self.assertEqual(User.objects.all().count(), 1) + + def test_attributes_override_create(self): + """Test that all model fields can be modified during creation""" + user = UserFactory( + email='hello@jambonsw.com', + password='my_secret_password87', + short_name='René', + full_name='René Magritte', + is_active=False, + is_staff=True, + is_superuser=True, + ) + self.assertIsInstance(user, User) + self.assertTrue(user.check_password('my_secret_password87')) + self.assertEqual(User.objects.all().count(), 1) diff --git a/tox.ini b/tox.ini index 23e014e..1e86784 100644 --- a/tox.ini +++ b/tox.ini @@ -49,7 +49,10 @@ setenv = PYTHONDONTWRITEBYTECODE=1 PYTHONWARNINGS=once deps = - coverage + coverage==4.4.1 + factory_boy==2.9.2 + Faker==0.7.18 + python-dateutil==2.6.1 django18: Django>=1.8,<1.9 django110: Django>=1.10,<1.11 django111: Django>=1.11,<2.0