Mixer -- Is a fixtures replacement. Supported Django, Flask, SqlAlchemy and custom python objects.

Overview

https://raw.github.com/klen/mixer/develop/docs/_static/logo.png

The Mixer is a helper to generate instances of Django or SQLAlchemy models. It's useful for testing and fixture replacement. Fast and convenient test-data generation.

Mixer supports:

Tests Status Version Downloads License

Docs are available at https://mixer.readthedocs.org/. Pull requests with documentation enhancements and/or fixes are awesome and most welcome.

Описание на русском языке: http://klen.github.io/mixer.html

Important

From version 6.2 the Mixer library doesn't support Python 2. The latest version with python<3 support is mixer 6.1.3

Requirements

  • Python 3.7+
  • Django (3.0, 3.1) for Django ORM support;
  • Flask-SQLALchemy for SQLAlchemy ORM support and integration as Flask application;
  • Faker >= 0.7.3
  • Mongoengine for Mongoengine ODM support;
  • SQLAlchemy for SQLAlchemy ORM support;
  • Peewee ORM support;

Installation

Mixer should be installed using pip:

pip install mixer

Usage

By default Mixer tries to generate fake (human-friendly) data.
If you want to randomize the generated values initialize the Mixer
by manual: Mixer(fake=False)
By default Mixer saves the generated objects in a database. If you want to disable
this, initialize the Mixer by manual like Mixer(commit=False)

Django workflow

Quick example:

from mixer.backend.django import mixer
from customapp.models import User, UserMessage

# Generate a random user
user = mixer.blend(User)

# Generate an UserMessage
message = mixer.blend(UserMessage, user=user)

# Generate an UserMessage and an User. Set username for generated user to 'testname'.
message = mixer.blend(UserMessage, user__username='testname')

# Generate SomeModel from SomeApp and select FK or M2M values from db
some = mixer.blend('someapp.somemodel', somerelation=mixer.SELECT)

# Generate SomeModel from SomeApp and force a value of money field from default to random
some = mixer.blend('someapp.somemodel', money=mixer.RANDOM)

# Generate 5 SomeModel's instances and take company field's values from custom generator
some_models = mixer.cycle(5).blend('somemodel', company=(name for name in company_names))

Flask, Flask-SQLAlchemy

Quick example:

from mixer.backend.flask import mixer
from models import User, UserMessage

mixer.init_app(self.app)

# Generate a random user
user = mixer.blend(User)

# Generate an userMessage
message = mixer.blend(UserMessage, user=user)

# Generate an UserMessage and an User. Set username for generated user to 'testname'.
message = mixer.blend(UserMessage, user__username='testname')

# Generate SomeModel and select FK or M2M values from db
some = mixer.blend('project.models.SomeModel', somerelation=mixer.SELECT)

# Generate SomeModel from SomeApp and force a value of money field from default to random
some = mixer.blend('project.models.SomeModel', money=mixer.RANDOM)

# Generate 5 SomeModel's instances and take company field's values from custom generator
some_models = mixer.cycle(5).blend('project.models.SomeModel', company=(company for company in companies))

Support for Flask-SQLAlchemy models that have __init__ arguments

For support this scheme, just create your own mixer class, like this:

from mixer.backend.sqlalchemy import Mixer

class MyOwnMixer(Mixer):

    def populate_target(self, values):
        target = self.__scheme(**values)
        return target

mixer = MyOwnMixer()

SQLAlchemy workflow

Example of initialization:

from mixer.backend.sqlalchemy import Mixer

ENGINE = create_engine('sqlite:///:memory:')
BASE = declarative_base()
SESSION = sessionmaker(bind=ENGINE)

mixer = Mixer(session=SESSION(), commit=True)
role = mixer.blend('package.models.Role')

Also, see Flask, Flask-SQLAlchemy.

Mongoengine workflow

Example usage:

from mixer.backend.mongoengine import mixer

class User(Document):
    created_at = DateTimeField(default=datetime.datetime.now)
    email = EmailField(required=True)
    first_name = StringField(max_length=50)
    last_name = StringField(max_length=50)
    username = StringField(max_length=50)

class Post(Document):
    title = StringField(max_length=120, required=True)
    author = ReferenceField(User)
    tags = ListField(StringField(max_length=30))

post = mixer.blend(Post, author__username='foo')

Marshmallow workflow

Example usage:

from mixer.backend.marshmallow import mixer
import marshmallow as ma

class User(ma.Schema):
    created_at = ma.fields.DateTime(required=True)
    email = ma.fields.Email(required=True)
    first_name = ma.fields.String(required=True)
    last_name = ma.fields.String(required=True)
    username = ma.fields.String(required=True)

class Post(ma.Schema):
    title = ma.fields.String(required=True)
    author = ma.fields.Nested(User, required=True)

post = mixer.blend(Post, author__username='foo')

Common usage

Quick example:

from mixer.main import mixer

class Test:
    one = int
    two = int
    name = str

class Scheme:
    name = str
    money = int
    male = bool
    prop = Test

scheme = mixer.blend(Scheme, prop__one=1)

DB commits

By default 'django', 'flask', 'mongoengine' backends tries to save objects in database. For preventing this behavior init mixer manually:

from mixer.backend.django import Mixer

mixer = Mixer(commit=False)

Or you can temporary switch context use the mixer as context manager:

from mixer.backend.django import mixer

# Will be save to db
user1 = mixer.blend('auth.user')

# Will not be save to db
with mixer.ctx(commit=False):
    user2 = mixer.blend('auth.user')

Custom fields

The mixer allows you to define generators for fields by manually. Quick example:

from mixer.main import mixer

class Test:
    id = int
    name = str

mixer.register(Test,
    name=lambda: 'John',
    id=lambda: str(mixer.faker.small_positive_integer())
)

test = mixer.blend(Test)
test.name == 'John'
isinstance(test.id, str)

# You could pinned just a value to field
mixer.register(Test, name='Just John')
test = mixer.blend(Test)
test.name == 'Just John'

Also, you can make your own factory for field types:

from mixer.backend.django import Mixer, GenFactory

def get_func(*args, **kwargs):
    return "Always same"

class MyFactory(GenFactory):
    generators = {
        models.CharField: get_func
    }

mixer = Mixer(factory=MyFactory)

Middlewares

You can add middleware layers to process generation:

from mixer.backend.django import mixer

# Register middleware to model
@mixer.middleware('auth.user')
def encrypt_password(user):
    user.set_password('test')
    return user

You can add several middlewares. Each middleware should get one argument (generated value) and return them.

It's also possible to unregister a middleware:

mixer.unregister_middleware(encrypt_password)

Locales

By default mixer uses 'en' locale. You could switch mixer default locale by creating your own mixer:

from mixer.backend.django import Mixer

mixer = Mixer(locale='it')
mixer.faker.name()          ## u'Acchisio Conte'

At any time you could switch mixer current locale:

mixer.faker.locale = 'cz'
mixer.faker.name()          ## u'Miloslava Urbanov\xe1 CSc.'

mixer.faker.locale = 'en'
mixer.faker.name()          ## u'John Black'

# Use the mixer context manager
mixer.faker.phone()         ## u'1-438-238-1116'
with mixer.ctx(locale='fr'):
    mixer.faker.phone()     ## u'08 64 92 11 79'

mixer.faker.phone()         ## u'1-438-238-1116'

Bug tracker

If you have any suggestions, bug reports or annoyances please report them to the issue tracker at https://github.com/klen/mixer/issues

Contributing

Development of mixer happens at Github: https://github.com/klen/mixer

Contributors

License

Licensed under a BSD license.

Comments
  • Support for Flask-SQLAlchemy models that have `__init__` arguments

    Support for Flask-SQLAlchemy models that have `__init__` arguments

    Consider the todo example from Flask-SQLAlchemy:

    from datetime import datetime
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from mixer.backend.sqlalchemy import mixer
    
    app = Flask(__name__)
    db = SQLAlchemy(app)
    
    class Todo(db.Model):
        __tablename__ = 'todos'
        id = db.Column('todo_id', db.Integer, primary_key=True)
        title = db.Column(db.String(60))
        text = db.Column(db.String)
        pub_date = db.Column(db.DateTime)
    
        def __init__(self, title, text):
            self.title = title
            self.text = text
            self.pub_date = datetime.utcnow()
    

    If we try to use mixer with it:

    mixer.blend(Todo)
    
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-1-8a1d24676132> in <module>()
         19         self.pub_date = datetime.utcnow()
         20
    ---> 21 mixer.blend(Todo)
    
    /Users/razzi/local/venvs/thornm/lib/python2.7/site-packages/mixer/main.pyc in blend(self, scheme, **values)
        596         type_mixer = self.get_typemixer(scheme)
        597         try:
    --> 598             return type_mixer.blend(**values)
        599         except Exception:
        600             if self.params.get('silence'):
    
    /Users/razzi/local/venvs/thornm/lib/python2.7/site-packages/mixer/main.pyc in blend(self, **values)
        145                 values.append((name, value))
        146
    --> 147         target = self.populate_target(values)
        148
        149         # Run registered middlewares
    
    /Users/razzi/local/venvs/thornm/lib/python2.7/site-packages/mixer/main.pyc in populate_target(self, values)
        168     def populate_target(self, values):
        169         """ Populate target with values. """
    --> 170         target = self.__scheme()
        171         for name, value in values:
        172             setattr(target, name, value)
    
    TypeError: __init__() takes exactly 3 arguments (1 given)
    

    mixer attempts to __init__ without any arguments, which throws an error. Would supporting a model defined this way be feasible/desirable?

    One way to get around this is to make all fields have defaults in the __init__:

    class User(Base):
        __tablename__ = 'users'
        id = Column(Integer, primary_key=True)
        name = Column(String(50), unique=True)
        email = Column(String(120), unique=True)
    
        def __init__(self, name=None, email=None):
            self.name = name
            self.email = email
    

    At the very least, putting a note in the docs that models with required __init__ parameters are unsupported might save others some confusion.

    opened by razzius 6
  • Postgres UUID

    Postgres UUID

    Mixer doesn't support sqlalchemy.dialects.postgresql.UUID. I'm make simple hotfix for it based on name. I can't make tests for it because mixer's tests uses only in memory sqlite database.

    opened by orsinium 5
  • Add django2 support. Drop django1.9. Update tox and readme

    Add django2 support. Drop django1.9. Update tox and readme

    This commit adds support for Django 2.0, which is now released. It also drops support for Django 1.9.

    More work will need to be done with the tox/travis setup if the author would like travis to test django2, as it requires python3 but the current travis config is python2 only.

    opened by Fingel 5
  • Prevent distasteful sample content

    Prevent distasteful sample content

    I'm using mixer to generate sample data for a software demo in a relatively conservative industry. As such, I don't want to be showing a demo of my software and have things like [email protected] (that's a real world example) show up as an email address - it makes us look immature when we're presenting our software to enterprise clients.

    I realize we're not going to eliminate the possibility of suggestive content getting populated from time to time, but I see no reason to invite it.

    Would you be open to removing some of the more explicit sample content, or providing a way to disable it? I'd be happy to do some of the work and submit a pull request, just wanted to ask first.

    opened by fuhrysteve 5
  • Incompatible with latest version of Faker (`12.1.0`)

    Incompatible with latest version of Faker (`12.1.0`)

    Using the latest version of Faker (12.1.0) raises the following exception:

    AttributeError: type object 'Factory' has no attribute '_get_provider_class'
    

    The latest version of Faker (published 11 hours ago) removed the method "_get_provider_class".

    This package uses _get_provider_class here: https://github.com/klen/mixer/blob/39ef3b717d4ac9da1824cb9c242fd326fa00ba08/mixer/_faker.py#L33

    Disallowing the latest version of Faker seems to fix the problem.

    opened by mtilda 4
  • Error when using a Marshmallow schema

    Error when using a Marshmallow schema

    I get the following error when I want to generate an object using a marshmallow schema:

    ValueError: Mixer (<class 'src.users.schemas.UserSchema'>): Generation for OPTIONS_CLASS (UserSchema) has been stopped. Exception: __init__() missing 1 required positional argument: 'meta'
    

    The code is:

    from marshmallow import Schema, fields
    from mixer.main import mixer
    
    class UserSchema(Schema):
        id = fields.Integer(read_only=True)
        email = fields.String()
        first_name = fields.String()
        last_name = fields.String()
    
    user = mixer.blend(UserSchema)
    

    I saw this issue open, which indicates this is not possible yet. But it is in the docs already here.

    Versions:

    python==3.7.0
    marshmallow==2.16.0
    mixer==6.1.3
    

    Full trace:

    Traceback (most recent call last):
      File "/usr/local/lib/python3.7/site-packages/mixer/main.py", line 241, in gen_value
        value = fab()
      File "/usr/local/lib/python3.7/site-packages/mixer/main.py", line 134, in blend
        target = self.populate_target(values)
      File "/usr/local/lib/python3.7/site-packages/mixer/main.py", line 157, in populate_target
        target = self.__scheme()
    TypeError: __init__() missing 1 required positional argument: 'meta'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/usr/local/lib/python3.7/site-packages/sanic/app.py", line 603, in handle_request
        response = await response
      File "/usr/src/src/users/views.py", line 19, in get
        create_user()
      File "/usr/src/src/users/factories.py", line 7, in create_user
        user = mixer.blend(UserSchema)
      File "/usr/local/lib/python3.7/site-packages/mixer/main.py", line 568, in blend
        return type_mixer.blend(**values)
      File "/usr/local/lib/python3.7/site-packages/mixer/main.py", line 116, in blend
        for name, value in defaults.items()
      File "/usr/local/lib/python3.7/site-packages/mixer/main.py", line 116, in <genexpr>
        for name, value in defaults.items()
      File "/usr/local/lib/python3.7/site-packages/mixer/mix_types.py", line 222, in gen_value
        return type_mixer.gen_field(field)
      File "/usr/local/lib/python3.7/site-packages/mixer/main.py", line 193, in gen_field
        return self.gen_value(field.name, field, unique=unique)
      File "/usr/local/lib/python3.7/site-packages/mixer/main.py", line 247, in gen_value
        field_name, self.__scheme.__name__, exc))
    ValueError: Mixer (<class 'src.users.schemas.UserSchema'>): Generation for OPTIONS_CLASS (UserSchema) has been stopped. Exception: __init__() missing 1 required positional argument: 'meta'
    

    Any help would be appreciated!

    opened by snoepkast 4
  • change SMALLINT to 32767

    change SMALLINT to 32767

    in mysql 32768 is too large for a small int, only 32767 is allowed. (ref - https://dev.mysql.com/doc/refman/8.0/en/integer-types.html) this causes a bug for me many times.

    opened by avi-pomicell 3
  • django 2.1+ support

    django 2.1+ support

    supporting django 2.1 for a project

    Mixer 6.0.1 version raises an exception while creating FK items in django 2.1:

    Traceback (most recent call last): File "", line 1, in File "/usr/local/lib/python3.6/site-packages/mixer/main.py", line 568, in blend return type_mixer.blend(**values) File "/usr/local/lib/python3.6/site-packages/mixer/main.py", line 116, in blend for name, value in defaults.items() File "/usr/local/lib/python3.6/site-packages/mixer/main.py", line 116, in for name, value in defaults.items() File "/usr/local/lib/python3.6/site-packages/mixer/backend/django.py", line 218, in get_value return self._get_value(name, value, field) File "/usr/local/lib/python3.6/site-packages/mixer/backend/django.py", line 233, in _get_value value = field.scheme.to_python(value) File "/usr/local/lib/python3.6/site-packages/django/db/models/fields/related.py", line 874, in to_python return self.target_field.to_python(value) File "/usr/local/lib/python3.6/site-packages/django/db/models/fields/init.py", line 945, in to_python params={'value': value}, django.core.exceptions.ValidationError: ["Значение 'Anna Stevens' должно быть целым числом."]

    This patch fix it

    opened by Mikhail517 3
  • Update django.py

    Update django.py

    This line: value = field.scheme.to_python(value) raises an Exception when you upgrade to django 2.1. I don't know why it happens, but this workaround fixed the tests for me :).

    opened by ephes 3
  • Fix small positive integer field limit

    Fix small positive integer field limit

    opened by jnns 3
  • make_fabric & cls_to_simple fixes

    make_fabric & cls_to_simple fixes

    few fixes to resolve issues with sqlalchemy + MySQL

    • mixer.factory.GenFactory#cls_to_simple does not handle dialects.

    if fcls is <class 'sqlalchemy.dialects.mysql.base.VARCHAR'> original function returns None with this fix it will return <class 'sqlalchemy.sql.sqltypes.VARCHAR'>

    • mixer.backend.sqlalchemy.TypeMixer#make_fabric TINYINT(1) should be boolean. original function generates TINYINT instead of BOOLEAN which may lead to errors
    opened by overborn 3
  • build(deps): update faker requirement from <12.1,>=5.4.0 to >=5.4.0,<15.4

    build(deps): update faker requirement from <12.1,>=5.4.0 to >=5.4.0,<15.4

    Updates the requirements on faker to permit the latest version.

    Release notes

    Sourced from faker's releases.

    Release v15.3.1

    See CHANGELOG.md.

    Changelog

    Sourced from faker's changelog.

    v15.3.1 - 2022-11-07

    v15.3.0 - 2022-11-07

    v15.2.0 - 2022-11-04

    v15.1.5 - 2022-11-04

    v15.1.4 - 2022-11-04

    • Remove test dependency on random2.

    v15.1.3 - 2022-11-01

    v15.1.2 - 2022-11-01

    • Fix missing return in en_US state_abbr. Thanks @​AssenD.

    v15.1.1 - 2022-10-13

    v15.1.0 - 2022-10-11

    v15.0.0 - 2022-09-26

    v14.2.1 - 2022-09-22

    • Fix misspelled first name in da_DK locale. Thanks @​filson1.

    v14.2.0 - 2022-08-31

    v14.1.2 - 2022-08-31

    ... (truncated)

    Commits

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies python 
    opened by dependabot[bot] 1
  • Don't restrict Faker to version < 12.1

    Don't restrict Faker to version < 12.1

    What is the reason to restrict Faker to a version below 12.1? Looking at the release notes of Faker, I would not expect any breaking changes. Maybe lift the restriction completely or at least raise it to the current (major-)version?

    opened by finsterwalder 4
  • Mixer should respect decimal presision on SQLAlchemy models

    Mixer should respect decimal presision on SQLAlchemy models

    I have model with field defined like this: Column(sa.Numeric(precision=9, scale=3), nullable=False) and I am trying to use Mixer to put data into that model. Sometimes it tries to insert larger values than allowed by this field which results with error:

    sqlalchemy.exc.DataError: Mixer (<class 'test.Model'>): (psycopg2.errors.NumericValueOutOfRange) numeric field overflow
    DETAIL:  A field with precision 9, scale 3 must round to an absolute value less than 10^6.
    
    opened by pax0r 0
  • docs: Fix a few typos

    docs: Fix a few typos

    There are small typos in:

    • mixer/_compat.py
    • mixer/auto.py
    • mixer/main.py
    • mixer/markov.py

    Fixes:

    • Should read happened rather than happend.
    • Should read deprecated rather than depricated.
    • Should read constructing rather than contructing.
    • Should read automatically rather than automaticly.

    Semi-automated pull request generated by https://github.com/timgates42/meticulous/blob/master/docs/NOTE.md

    opened by timgates42 0
Owner
Kirill Klenov
Kirill Klenov
A test fixtures replacement for Python

factory_boy factory_boy is a fixtures replacement based on thoughtbot's factory_bot. As a fixtures replacement tool, it aims to replace static, hard t

FactoryBoy project 3k Jan 5, 2023
A test fixtures replacement for Python

factory_boy factory_boy is a fixtures replacement based on thoughtbot's factory_bot. As a fixtures replacement tool, it aims to replace static, hard t

FactoryBoy project 2.4k Feb 5, 2021
A test fixtures replacement for Python

factory_boy factory_boy is a fixtures replacement based on thoughtbot's factory_bot. As a fixtures replacement tool, it aims to replace static, hard t

FactoryBoy project 2.4k Feb 8, 2021
A set of pytest fixtures to test Flask applications

pytest-flask An extension of pytest test runner which provides a set of useful tools to simplify testing and development of the Flask extensions and a

pytest-dev 433 Dec 23, 2022
A set of pytest fixtures to test Flask applications

pytest-flask An extension of pytest test runner which provides a set of useful tools to simplify testing and development of the Flask extensions and a

pytest-dev 354 Feb 17, 2021
User-interest mock backend server implemnted using flask restful, and SQLAlchemy ORM confiugred with sqlite

Flask_Restful_SQLAlchemy_server User-interest mock backend server implemnted using flask restful, and SQLAlchemy ORM confiugred with sqlite. Backend b

Austin Weigel 1 Nov 17, 2022
Redis fixtures and fixture factories for Pytest.

Redis fixtures and fixture factories for Pytest.This is a pytest plugin, that enables you to test your code that relies on a running Redis database. It allows you to specify additional fixtures for Redis process and client.

Clearcode 86 Dec 23, 2022
It helps to use fixtures in pytest.mark.parametrize

pytest-lazy-fixture Use your fixtures in @pytest.mark.parametrize. Installation pip install pytest-lazy-fixture Usage import pytest @pytest.fixture(p

Marsel Zaripov 299 Dec 24, 2022
pytest_pyramid provides basic fixtures for testing pyramid applications with pytest test suite

pytest_pyramid pytest_pyramid provides basic fixtures for testing pyramid applications with pytest test suite. By default, pytest_pyramid will create

Grzegorz Śliwiński 12 Dec 4, 2022
HTTP load generator, ApacheBench (ab) replacement, formerly known as rakyll/boom

hey is a tiny program that sends some load to a web application. hey was originally called boom and was influenced from Tarek Ziade's tool at tarekzia

Jaana Dogan 14.9k Jan 7, 2023
A friendly wrapper for modern SQLAlchemy and Alembic

A friendly wrapper for modern SQLAlchemy (v1.4 or later) and Alembic. Documentation: https://jpsca.github.io/sqla-wrapper/ Includes: A SQLAlchemy wrap

Juan-Pablo Scaletti 129 Nov 28, 2022
Django-google-optimize is a Django application designed to make running server side Google Optimize A/B tests easy.

Django-google-optimize Django-google-optimize is a Django application designed to make running Google Optimize A/B tests easy. Here is a tutorial on t

Adin Hodovic 39 Oct 25, 2022
create custom test databases that are populated with fake data

About Generate fake but valid data filled databases for test purposes using most popular patterns(AFAIK). Current support is sqlite, mysql, postgresql

Emir Ozer 2.2k Jan 4, 2023
A toolbar overlay for debugging Flask applications

Flask Debug-toolbar This is a port of the excellent django-debug-toolbar for Flask applications. Installation Installing is simple with pip: $ pip ins

null 863 Dec 29, 2022
Test django schema and data migrations, including migrations' order and best practices.

django-test-migrations Features Allows to test django schema and data migrations Allows to test both forward and rollback migrations Allows to test th

wemake.services 382 Dec 27, 2022
A Django plugin for pytest.

Welcome to pytest-django! pytest-django allows you to test your Django project/applications with the pytest testing tool. Quick start / tutorial Chang

pytest-dev 1.1k Dec 31, 2022
Silky smooth profiling for Django

Silk Silk is a live profiling and inspection tool for the Django framework. Silk intercepts and stores HTTP requests and database queries before prese

Jazzband 3.7k Jan 4, 2023
Django test runner using nose

django-nose django-nose provides all the goodness of nose in your Django tests, like: Testing just your apps by default, not all the standard ones tha

Jazzband 880 Dec 15, 2022
Useful additions to Django's default TestCase

django-test-plus Useful additions to Django's default TestCase from REVSYS Rationale Let's face it, writing tests isn't always fun. Part of the reason

REVSYS 546 Dec 22, 2022