# Create shared test data in setUpTestData instead of setUp

> Django runs setUp before every test, so its rows are inserted again each time. setUpTestData creates them once per TestCase class, and every test still starts clean.

`setUp()` runs before every test method. When it creates database rows (a user, an organization, a few projects with their tasks) a class with 30 tests creates them 30 times, and throws them away 30 times. Often most of a test's time goes into setup that's identical for every test in the class.

Django's `TestCase` has a class-level hook for exactly this: `setUpTestData()` runs once per class, and every test still sees the data exactly as it was created.

## Why setUp is slow

Everything in `setUp` is repeated per test: each `baker.make()` or `Model.objects.create()` is an `INSERT` (often several, with related objects), each `create_user(password=...)` hashes a password, and each factory may run signals and post-generation hooks. The work is small for one test and large for a suite. A `setUp` that takes 50 ms in a class of 40 tests costs 2 seconds, and a project has many such classes.

## The fix

Move objects that tests only read into `setUpTestData`, a classmethod that assigns to `cls`:

```python
# Before: runs before each of the class's tests
from django.test import TestCase
from model_bakery import baker

from projects.models import Organization, Project


class ProjectListTests(TestCase):
    def setUp(self):
        self.org = baker.make(Organization)
        self.user = baker.make("auth.User")
        self.org.members.add(self.user)
        self.projects = baker.make(Project, organization=self.org, _quantity=20)
        self.client.force_login(self.user)
```

```python
# After: data is created once for the class
from django.test import TestCase
from django.urls import reverse
from model_bakery import baker

from projects.models import Organization, Project


class ProjectListTests(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.org = baker.make(Organization)
        cls.user = baker.make("auth.User")
        cls.org.members.add(cls.user)
        cls.projects = baker.make(Project, organization=cls.org, _quantity=20)

    def setUp(self):
        self.client.force_login(self.user)

    def test_lists_projects(self):
        response = self.client.get(reverse("project-list", args=[self.org.slug]))
        self.assertEqual(len(response.context["projects"]), 20)
```

Tests keep using `self.org` and `self.user` as before. `force_login` stays in `setUp`: the test client is created fresh for every test, so its session has to be set up per test, and it doesn't touch the slow parts (see [fast password hashing](https://flakytest.dev/guides/fast-password-hasher-in-tests/) for why `force_login` beats `login`).

## Why each test still starts clean

`TestCase` wraps the whole class in a transaction, runs `setUpTestData` inside it, and wraps each test in a savepoint. When a test ends, Django rolls back to the savepoint:

- rows a test inserts, updates or deletes are back to how `setUpTestData` left them for the next test
- since Django 3.2, the objects assigned to `cls` are deep-copied for each test the first time it reads them, so `self.org.name = "changed"` in one test doesn't leak into the next

You don't have to `refresh_from_db()` between tests. The deep copy has a cost of its own when the attributes are large: [setUpTestData deep copies](https://flakytest.dev/guides/setuptestdata-deepcopy/) explains what to keep out of them.

## What stays in setUp

`setUpTestData` is for database rows. Keep per-test work in `setUp`:

- logging in with the test client (`force_login`)
- `unittest.mock` patches that must start and stop per test
- temporary files and directories
- anything outside the database that the test changes: cache entries, files in `MEDIA_ROOT`, a search index. The rollback doesn't undo those, so creating them once per class would let tests see each other's changes.

## With pytest-style tests

pytest-django's `db` fixture is function-scoped, so a class- or module-scoped pytest fixture can't use the database the same way. You have two options:

- Keep `TestCase` classes for the tests that share expensive data. pytest runs them as usual, `setUpTestData` included.
- For read-only data every test needs (countries, plans, permissions), load it once for the whole session by extending `django_db_setup`; see [loading fixtures once](https://flakytest.dev/guides/django-fixture-loading/).

To make the remaining per-test data cheaper, create it in bulk: [faster test factories](https://flakytest.dev/guides/faster-test-factories/).

## Keep the tests correct

- Attributes assigned in `setUpTestData` are deep-copied per test, so in-memory changes don't leak between tests. Objects that can't be deep-copied (locks, open files, some clients) raise a `TypeError` when a test reads them; create those in `setUp` or at module level.
- Changes a test saves to the database are rolled back, but only inside `TestCase`. `TransactionTestCase` has no `setUpTestData`, and on a database without transactions (MySQL with MyISAM) Django calls `setUpTestData` before every test, so there is no speed-up.
- Move one class at a time and run the suite in random order (with pytest-randomly installed, or `manage.py test --shuffle`) to catch tests that depended on running after another test.

## How flakytest finds it

flakytest measures the time spent in `setUp` methods in your test files. When it's at least half a second and 2% of test time, in classes with more than one test, it suggests **Create shared test data in setUpTestData instead of setUp**. The summary breaks `setUp`'s time down by category (for example *database* and *password hashing*) and names the classes with the most to gain, with their test counts. Run `flakytest run` again after moving the data and `flakytest compare` shows which tests got faster and that none of them changed outcome.

## Further reading

- [Django: `TestCase.setUpTestData()`](https://docs.djangoproject.com/en/stable/topics/testing/tools/#django.test.TestCase.setUpTestData)
- [Django: TestCase](https://docs.djangoproject.com/en/stable/topics/testing/tools/#testcase)
- [model_bakery documentation](https://model-bakery.readthedocs.io/en/latest/)
