This project has moved: https://gitlab.com/gorilladev/pytest-django-ifactory
Mattias Jakobsson 5362f7b4c6 Added test case with model containing all non-postgres fields | 6 gadi atpakaļ | |
---|---|---|
pytest_django_ifactory | 6 gadi atpakaļ | |
tests | 6 gadi atpakaļ | |
.gitignore | 6 gadi atpakaļ | |
.pre-commit-config.yaml | 6 gadi atpakaļ | |
LICENSE | 6 gadi atpakaļ | |
MANIFEST.in | 6 gadi atpakaļ | |
README.md | 6 gadi atpakaļ | |
pyproject.toml | 6 gadi atpakaļ | |
requirements.txt | 6 gadi atpakaļ | |
setup.cfg | 6 gadi atpakaļ | |
setup.py | 6 gadi atpakaļ | |
tox.ini | 6 gadi atpakaļ |
A model instance factory for pytest-django.
pytest-django-ifactory makes it easy to create model instances for your test cases even if they contain a lot of non-nullable fields and complex foreign key relationships. If you every felt like you spent too much time coming up with dummy values for you models' fields just to get an instance into the database to use with a test then pytest-django-ifactory might be for you.
pytest's fixtures are great and perfect if you want to have a static model instance available in the database for your tests. Problems arise however when you want to vary one of its fields. To reuse your fixture in that case you need to modify the field and save the instance back to the database (assuming your test needs it in the database, of course). This results in at least two lines of extra setup code in you test case and an extra call to the database.
pytest-django-ifactory is simply an instance factory (hence ifactory) function that automatically detects your Django models and tries to come up with acceptable defaults for the fields you don't care about. This includes generating unique values for fields marked as unique and to create related instances for non-nullable foreign keys.
Note that this library is very much in alpha and its API may change in future versions.
This plugin comes with a single fixture: ifactory
. Use it when you
need to put model instances in the database. Below is a contrived
example to test a function that finds duplicate names of you users:
from itertools import groupby
from operator import methodcaller
from django.contrib.auth.models import User
def get_duplicate_names():
all_users = User.objects.order_by("last_name", "first_name")
users_by_name = groupby(all_users, methodcaller("get_full_name"))
return [full_name for full_name, users in users_by_name if len(list(users)) > 1]
def test_get_duplicate_names(ifactory):
ifactory.auth.user(first_name="Albert", last_name="Einstein")
ifactory.auth.user(first_name="Albert", last_name="Einstein")
ifactory.auth.user(first_name="Erwin", last_name="Schrodinger")
ifactory.auth.user(first_name="Richard", last_name="Feynman")
assert get_duplicate_names() == ["Albert Einstein"]
assert User.objects.count() == 4
You find you models namespaced by the application name and the model
name on the ifactory
instance. For instance, if you have created a
Book
model in a library
application (and put your library
application in INSTALLED_APPS), its factory function will be
ifactory.library.book()
. This function accepts the same arguments as
your model constructor does and returns the created instance.
Notice in the example above that we create four new users without specifying their unique usernames. The goal of this project is that you should never have to specify the value of a field if you're not interested in that value in your test. Conversely, you should never rely on a value you haven't explicity set. This library gives no guarantees that the value it chooses for a field will be the same the next time the test is run. It just tries to make sure that the instance can be saved to the database without any integrity errors.
While I would strongly recommend against it, if you do want to know
which default value will be used, you can use the
pytest_django_ifactory_configure
hook. A good place to put it is in
your conftest.py:
def pytest_django_ifactory_configure(ifactory):
ifactory.configure_defaults("auth.user", {
"first_name": "Albert",
"last_name": "Einstein",
})
From now on, all users in your tests will be Albert Einstein unless you say otherwise:
def test_albert_by_default(ifactory):
albert = ifactory.auth.user()
assert albert.get_full_name() == "Albert Einstein"
not_albert = ifactory.auth.user(first_name="Erwin", last_name="Schrodinger")
assert not_albert.full_name() == "Erwin Schrodinger"
While the above example might not be the best idea as your test suit grows the hook can be used to enforce constraints in your models that this library is unaware of, e.g., validation errors raised by your models that depend on the model's field values.
This project uses black to auto-format the code, flake8 to check it, pytest and tox to test it, and finally check-manifest to check the project's MANIFEST.in. To facilitate (and remember) to actually run all these tools, pre-commit is used. Hence, the only two hard development requirements are pre-commit and tox. Install them and run
$ pre-commit install
once the first time you check out the repo and from now on all checks except the unit tests will be run everytime a commit is made. The unit tests are run manually with tox
$ tox
Tox runs the tests with Python 2.7 and 3.4-3.7, so to run all of them you need separate installations of all these Python versions.
If you want to install all development requirements to run them
manually (and without using pre-commit run --all-files
), use the
requirements.txt file:
$ pip install -r requirements.txt
Like pytest-django, pytest-django-ifactory is released under the BSD 3-clause license.