Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to pytest command #168

Merged
merged 1 commit into from
Jun 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 37 additions & 10 deletions app_helper/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,40 @@ class BaseTestCaseMixin:

@classmethod
def setUpClass(cls):
cls._setup_utils()
cls._setup_users()
super().setUpClass()

@classmethod
def _setup_utils(cls):
"""
Setup generic utils as class attributes.

* :py:attr:`request_factory`: instance of :py:class:`RequestFactory`
* :py:attr:`site_1`: instance of the first ``Django`` :py:class:`Site`
* :py:attr:`languages`: list of configured languages
"""
from django.contrib.sites.models import Site

cls.request_factory = RequestFactory()
cls.site_1 = Site.objects.all().first()

try:
from cms.utils import get_language_list

cls.languages = get_language_list()
except ImportError:
cls.languages = [x[0] for x in settings.LANGUAGES]

@classmethod
def _setup_users(cls):
"""
Create standard users.

* :py:attr:`user`: superuser
* :py:attr:`user_staff`: staff user
* :py:attr:`user_normal`: plain django user
"""
cls.user = create_user(
cls._admin_user_username,
cls._admin_user_email,
Expand All @@ -96,21 +127,17 @@ def setUpClass(cls):
cls.user_normal = create_user(
cls._user_user_username, cls._user_user_email, cls._user_user_password, is_staff=False, is_superuser=False,
)
cls.site_1 = Site.objects.all().first()

try:
from cms.utils import get_language_list

cls.languages = get_language_list()
except ImportError:
cls.languages = [x[0] for x in settings.LANGUAGES]
super().setUpClass()
@classmethod
def _teardown_users(cls):
"""Delete existing users."""
User = get_user_model() # NOQA
User.objects.all().delete()

@classmethod
def tearDownClass(cls):
super().tearDownClass()
User = get_user_model() # NOQA
User.objects.all().delete()
cls._teardown_users()

@contextmanager
def temp_dir(self):
Expand Down
14 changes: 13 additions & 1 deletion app_helper/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,25 @@ def setup(app, helper_module, extra_args=None, use_cms=False):
:param use_cms: setup a django CMS environemtn
:return: Django settings module
"""

def _pytest_setup(settings, module):
for setting in dir(settings):
if setting.isupper():
setting_value = getattr(settings, setting)
if setting == "SECRET_KEY" and not setting_value:
setting_value = "SECRET"
setattr(module, setting, setting_value)

helper = helper_module.__file__
argv = [os.path.basename(helper), app, "setup", "--extra-settings={}".format(helper)]
if use_cms:
argv.append("--cms")
if extra_args:
argv.extend(extra_args)
return runner(argv)
settings = runner(argv)
if "pytest_django" in sys.modules:
_pytest_setup(settings, helper_module)
return settings


def runner(argv):
Expand Down
1 change: 1 addition & 0 deletions changes/167.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support to pytest command
4 changes: 4 additions & 0 deletions docs/basetest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ repetitive tasks during development.
:members:
:private-members:

.. automethod:: app_helper.base_test.BaseTestCase._setup_users
.. automethod:: app_helper.base_test.BaseTestCase._teardown_users
.. automethod:: app_helper.base_test.BaseTestCase._setup_utils

.. autoattribute:: app_helper.base_test.BaseTestCase._admin_user_username
.. autoattribute:: app_helper.base_test.BaseTestCase._admin_user_password
.. autoattribute:: app_helper.base_test.BaseTestCase._admin_user_email
Expand Down
58 changes: 49 additions & 9 deletions docs/pytest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
pytest support
##############

While its :py:class:`BaseTestCaseMixin` is built on Django ``TestCase``,
``django-app-helper`` can be used with pytest-based tests by using the provided
compatible runner as documented on `pytest-django`_ documentation.
While django-app-helper was born with Django ``TestCase`` in mind, it can be used with ``pytest`` with some configuration
together with ``pytest-django``.

To enable pytest compatible runner:
************************
django-app-helper runner
************************

* Add to project ``helper.py`` file:
You can run pytest tests by using a custom runner (based on `pytest-django`_ documentation); to enable it,
add the following to project ``helper.py`` file:

.. code-block:: python

Expand All @@ -18,12 +20,15 @@ To enable pytest compatible runner:
...
}

* Run tests as usual::
Using this approach you can mix pytest tests and Django ``TestCase`` ones, the runner will take care
of discovering and running both.

$ python helper.py <app-name> test
Running tests
==============

You can also mix pytest tests and Django ``TestCase`` ones, the runner will take care
of discovering and running both.
Invoke ``app_helper`` as usual::

$ python helper.py <app-name> test

pytest options
==============
Expand Down Expand Up @@ -51,3 +56,38 @@ In case arguments are passed via both channels they are merged together, with ru
over environment variables in case of overlapping options.

.. _pytest-django: https://pytest-django.readthedocs.io/en/latest/faq.html#how-can-i-use-manage-py-test-with-pytest-django

***************
standard pytest
***************

Running tests
==============

Invoke ``pytest`` as usual::

$ python -mpytest <args>

or::

$ pytest <args>

In this case you don't need any special syntax to pass commands as the
django-app-helper pytest runner is not executed and pytest is full in control.

.. warning: the ``pytest`` invocation will only works if you add the current directory in the ``PYTHONPATH``, thus the
``python -mpytest`` version is preferred.

Using BaseTestCaseMixin
=======================

While its :py:class:`~app_helper.base_test.BaseTestCaseMixin` is built on Django ``TestCase``, it can be used in pytest classes:

Fixtures, markers and decorators can be used as usual on test methods as in classic pytest classes.

.. code-block:: python

class TestTags(BaseTestCaseMixin):
...
def test_foo(self):
...