Merge pull request #79 from oussjarrousse/78-adding-tests
78 adding tests
This commit is contained in:
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,5 +1,9 @@
|
||||
.idea
|
||||
example/venv
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
@@ -105,3 +109,6 @@ venv.bak/
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
example/test_db
|
||||
|
||||
# OS related
|
||||
.DS_Store
|
||||
|
||||
39
README.md
39
README.md
@@ -11,6 +11,7 @@ A Django app that handles MFA, it supports TOTP, U2F, FIDO2 U2F (Web Authn), Ema
|
||||
[](https://anaconda.org/conda-forge/django-mfa2)
|
||||
[](https://anaconda.org/conda-forge/django-mfa2)
|
||||
|
||||
|
||||
Web Authencation API (WebAuthn) is state-of-the art techology that is expected to replace passwords.
|
||||
|
||||

|
||||
@@ -196,6 +197,43 @@ function some_func() {
|
||||
|
||||
````
|
||||
|
||||
# Testing
|
||||
|
||||
We use `pytest` and several pytest plugins, especially the `pytest-django` and `pytest-cov` plugins that provide Django fixtures, and test coverage analysis.
|
||||
|
||||
In the root folder, `pytest.ini` contains configurations for running the tests, `requirements_testing.txt` contains the python packages required for running tests, and the folder `tests` contains the actual test files.
|
||||
|
||||
To run the tests, install the packages in requirements and requirements_testing.txt:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt -r requirements_testing.txt
|
||||
```
|
||||
|
||||
then simply run pytest
|
||||
```
|
||||
pytest
|
||||
```
|
||||
|
||||
to generate the coverage html pages:
|
||||
|
||||
```
|
||||
pytest --cov=. --cov-report html -v
|
||||
```
|
||||
|
||||
the coverage html files will be generated in the `htmlcov` folder
|
||||
|
||||
We use `tox` to test the package against different isolated environments. `tox.ini` contains the configurations for tox. To run the tests in the environments defined in the `tox.ini` file, make sure the python package tox is installed:
|
||||
|
||||
```
|
||||
pip install tox
|
||||
```
|
||||
|
||||
then run tox in the project root:
|
||||
|
||||
```
|
||||
tox
|
||||
```
|
||||
|
||||
# Contributors
|
||||
* [mahmoodnasr](https://github.com/mahmoodnasr)
|
||||
* [d3cline](https://github.com/d3cline)
|
||||
@@ -207,6 +245,7 @@ function some_func() {
|
||||
* [ezrajrice](https://github.com/ezrajrice)
|
||||
* [Spitfireap](https://github.com/Spitfireap)
|
||||
* [peterthomassen](https://github.com/peterthomassen)
|
||||
* [oussjarrousse](https://github.com/oussjarrousse)
|
||||
* [jkirkcaldy](https://github.com/jkirkcaldy)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.apps import AppConfig
|
||||
class myAppNameConfig(AppConfig):
|
||||
name = 'mfa'
|
||||
verbose_name = 'A Much Better Name'
|
||||
verbose_name = 'Django MFA2'
|
||||
@@ -1,3 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
109
pytest.ini
Normal file
109
pytest.ini
Normal file
@@ -0,0 +1,109 @@
|
||||
[pytest]
|
||||
# Searching
|
||||
python_files = test_*
|
||||
python_classes = Tests*
|
||||
python_functions = test_*
|
||||
|
||||
env_files =
|
||||
.env
|
||||
|
||||
# do not search for tests in these folders
|
||||
norecursedirs = .vscode .tox docs example img mfa venv .coverage django_mfa2.egg-info
|
||||
|
||||
# Add folder to PYTHONPATH
|
||||
# requires pytest >= 7.0.0
|
||||
pythonpath = .
|
||||
|
||||
|
||||
# https://pytest-django.readthedocs.io/en/latest/usage.html
|
||||
DJANGO_SETTINGS_MODULE = tests.settings
|
||||
|
||||
|
||||
# do not override the debug mode (True/False) set in the django settings module
|
||||
# https://pytest-django.readthedocs.io/en/latest/usage.html#additional-pytest-ini-settings
|
||||
django_debug_mode = keep
|
||||
|
||||
|
||||
#
|
||||
# set env variables
|
||||
# https://tech.serhatteker.com/post/2020-02/test-env-vars-in-python/
|
||||
# https://github.com/pytest-dev/pytest-env
|
||||
; env =
|
||||
; KEY=value
|
||||
|
||||
|
||||
addopts =
|
||||
# verbose
|
||||
-v
|
||||
# more verbosity
|
||||
# -vv
|
||||
# Don't show warnings
|
||||
# -p no:warnings
|
||||
# generates coverage report
|
||||
# note that enabling pytest coverage will cause debugging pytest to fail on pycharm
|
||||
# add the --no-cov to the pytest configuration on pycharm to allow for debugging pytest
|
||||
--cov=./mfa
|
||||
# surpress generating converage if one or more tests failed
|
||||
; --no-cov-on-fail
|
||||
# do not run migrations => faster test initialization
|
||||
# --nomigrations
|
||||
# Show hypthesis statistics whereever hypothesis was used
|
||||
# ignore these tests/files when looking for tests
|
||||
#--ignore=
|
||||
# black
|
||||
# --black
|
||||
--hypothesis-show-statistics
|
||||
# Add --reuse-db if you want to speed up tests by reusing the database between test runs.
|
||||
#--reuse-db
|
||||
|
||||
|
||||
# Define additional pytest markers so that using them in test will not trigger warnings
|
||||
# To show the help line use: % pytest --marker
|
||||
# To run pytest on a specifc marker use: pytest -m mark
|
||||
# to run pytestt on several markers use quotation and logic operators as in:
|
||||
# pytest -m "mark1 and mark2"
|
||||
# pytest -m "mark1 or mark2"
|
||||
# pytest -m "mark1 and not mark2"
|
||||
markers =
|
||||
API: tests of server api functions whether it is exposed as REST API or otherwise
|
||||
BLACK_BOX: Black Box tests
|
||||
WHITE_BOX: White Box tests
|
||||
ENVIRONMENT: tests for the environment
|
||||
CONFIGURATION: tests related configurations
|
||||
LOGGING: tests related to logging
|
||||
UNIT: Unit tests
|
||||
INTEGRATION: Integration testing
|
||||
UTILS: tests for utilities
|
||||
FOCUS: tests under the microscope... under the spotlight... in focus
|
||||
FUNC: functional teesting
|
||||
REGRESSION: tests for fixed bugs
|
||||
|
||||
DJANGO: tests related to DJANGO
|
||||
|
||||
HTTP_REQUEST: tests of functions that handles HTTP REQUESTS
|
||||
HTTP_GET: tests of functions that handles HTTP_GET_REQUESTS
|
||||
HTTP_POST: tests of functions that handles HTTP_POST_REQUESTS
|
||||
AUTH: tests related to user authentication
|
||||
SQL_DB: tests related to the sql database
|
||||
|
||||
CLI: tests related to flask-cli
|
||||
SERVER: tests for the server
|
||||
|
||||
API_V1: API related tests
|
||||
|
||||
PRIVILEGED_USER: tests for privileged users
|
||||
NON_PRIVILEGED_USER: tests for non-privileged users
|
||||
PERMISSIONS: tests related to permissions
|
||||
|
||||
ANNONYMOUS_USER: tests for non-authenticated users
|
||||
AUTHENTICATED_USER: tests for authenticated users
|
||||
|
||||
ENDPOINTS: tests for endpoints (API nodes)
|
||||
SERIALIZERS: tests for serializers
|
||||
VIEWS: tests for DRF viewsets
|
||||
FILTERS: tests for DRF filters
|
||||
MODELS: tests for models
|
||||
VALIDATORS: tests for validators
|
||||
|
||||
ERROR_HANDLING: tests for error handling
|
||||
SECURITY: tests for security
|
||||
10
requirements_testing.txt
Normal file
10
requirements_testing.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
tox
|
||||
pytest>=7.0.0
|
||||
pytest-xdist
|
||||
pytest-cov # Test coverage
|
||||
pytest-dotenv # plugin to load environment from .env file
|
||||
pytest-env # plugin to allow passing environment variable to pytest environmentt
|
||||
pytest-mock # plugin that provides a mocker fixture which is a thin-wrapper around the patching API provided by the mock package
|
||||
hypothesis # plugin that helps in automatize generating random values instead of static values in pyttests
|
||||
pytest-django # pytest support for Django
|
||||
validators # a package containing several validator functions
|
||||
2
setup.py
2
setup.py
@@ -14,7 +14,7 @@ setup(
|
||||
url = 'https://github.com/mkalioby/django-mfa2/',
|
||||
download_url='https://github.com/mkalioby/django-mfa2/',
|
||||
license='MIT',
|
||||
packages=find_packages(),
|
||||
packages=find_packages(exclude=("tests",)),
|
||||
install_requires=[
|
||||
'django >= 2.0',
|
||||
'simplejson',
|
||||
|
||||
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
19
tests/conftest.py
Normal file
19
tests/conftest.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import pytest
|
||||
|
||||
# @pytest.fixture
|
||||
# def api_request(rf):
|
||||
# request = rf.get('/url')
|
||||
# # Modify the request object as needed (e.g., set user, add data)
|
||||
# return request
|
||||
|
||||
# @pytest.fixture
|
||||
# def create_test_model(db):
|
||||
# def make_model(**kwargs):
|
||||
# return MyModel.objects.create(**kwargs)
|
||||
# return make_model
|
||||
|
||||
@pytest.fixture
|
||||
def authenticated_user(client, django_user_model):
|
||||
user = django_user_model.objects.create_user(username='test', password='123')
|
||||
client.login(username='test', password='123')
|
||||
return user
|
||||
51
tests/settings.py
Normal file
51
tests/settings.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import os
|
||||
|
||||
|
||||
SECRET_KEY = 'fake-key-for-testing'
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'mfa'
|
||||
]
|
||||
ROOT_URLCONF="mfa.urls"
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': ':memory:',
|
||||
}
|
||||
}
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [
|
||||
os.path.join(BASE_DIR ,'mfa','templates' ),
|
||||
os.path.join(BASE_DIR ,'tests','templates' )
|
||||
],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
MFA_UNALLOWED_METHODS = []
|
||||
11
tests/templates/base.html
Normal file
11
tests/templates/base.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
29
tests/test_views.py
Normal file
29
tests/test_views.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import pytest
|
||||
from django.urls import reverse
|
||||
|
||||
@pytest.mark.VIEWS
|
||||
@pytest.mark.DJANGO
|
||||
@pytest.mark.ANNONYMOUS_USER
|
||||
@pytest.mark.django_db
|
||||
def test_index_unauthenticated(client):
|
||||
url = reverse("mfa_home")
|
||||
response = client.get(url)
|
||||
assert response is not None
|
||||
assert response.status_code == 302
|
||||
assert response.url=="/accounts/login/?next=/"
|
||||
|
||||
@pytest.mark.VIEWS
|
||||
@pytest.mark.AUTHENTICATED_USER
|
||||
@pytest.mark.django_db
|
||||
def test_index_authenticated(client, authenticated_user):
|
||||
url = reverse("mfa_home")
|
||||
response = client.get(url)
|
||||
assert response is not None
|
||||
assert response.status_code == 200
|
||||
assert isinstance(response.templates, list)
|
||||
assert len(response.templates) == 4
|
||||
for template in response.templates:
|
||||
assert template.name in ["modal.html", "base.html", "mfa_base.html", "MFA.html"]
|
||||
|
||||
|
||||
|
||||
45
tox.ini
Normal file
45
tox.ini
Normal file
@@ -0,0 +1,45 @@
|
||||
# Tox (https://tox.readthedocs.io/) is a tool for running tests
|
||||
# in multiple virtualenvs. This configuration file will run the
|
||||
# test suite on all supported python versions. To use it, "pip install tox"
|
||||
# and then run "tox" from this directory.
|
||||
#
|
||||
# See also https://tox.readthedocs.io/en/latest/config.html for more
|
||||
# configuration options.
|
||||
|
||||
[tox]
|
||||
# Choose your Python versions. They have to be available
|
||||
# on the system the tests are run on.
|
||||
# comma separated
|
||||
envlist =
|
||||
python{3.6,3.7,3.8,3.9}-django3
|
||||
python{3.8,3.9,3.10,3.11}-django4
|
||||
python{3.8,3.9,3.10,3.11}-django5
|
||||
|
||||
# Tell tox to not require a setup.py file
|
||||
;skipsdist = True
|
||||
|
||||
isolated_build = True
|
||||
|
||||
[testenv]
|
||||
# https://tox.wiki/en/latest/example/basic.html#using-a-different-default-pypi-url
|
||||
;setenv =
|
||||
; PIP_INDEX_URL = https://pypi.my-alternative-index.org
|
||||
|
||||
# https://tech.serhatteker.com/post/2020-02/test-env-vars-in-python/
|
||||
;setenv =
|
||||
; NAME=value
|
||||
|
||||
# https://tox.wiki/en/latest/example/basic.html#passing-down-environment-variables
|
||||
# passenv = ENV_VAR_NAME
|
||||
|
||||
# https://tox.wiki/en/latest/example/pytest.html#extended-example-change-dir-before-test-and-use-per-virtualenv-tempdir
|
||||
;changedir = tests
|
||||
|
||||
deps =
|
||||
-rrequirements.txt
|
||||
-rrequirements_testing.txt
|
||||
|
||||
# https://tox.wiki/en/latest/example/basic.html#ignoring-a-command-exit-code
|
||||
commands =
|
||||
; pytest --junitxml=report.xml
|
||||
pytest {posargs}
|
||||
Reference in New Issue
Block a user