Passed Run of Nov 7, 23:53
Where the time goes
Test time by category- Database11.60 s
- Libraries6.01 s
- Migrations3.16 s
- Password hashing2.37 s
- DB schema1.15 s
- Templates1.10 s
- Imports542 ms
- App code337 ms
- Deep copies287 ms
- Serialization223 ms
- pytest174 ms
- Unsampled170 ms
- Test code26 ms
- Factories21 ms
- Waiting15 ms
- Mocking3 ms
- Cache3 ms
- Logging3 ms
Session timeline
Fix next
Ranked by the time each fix saves per runRun tests in parallel on all 2 CPUs
Tests run one at a time: 27.2s of test time on a 2-CPU machine. With pytest-xdist this could take about 13.6s.
Details
Tests must not share state: files in fixed paths, ports, a shared database without per-worker names, or module globals. Run with -p randomly first to shake out order dependencies.
Use plain static file storage in tests
Static file storage/manifest handling costs 12.7s.
Details
Where:
- apps/api/tests.py:487 ProfileUploadTest.upload · 704 ms
- apps/mcp/tests.py:67 McpTest.post · 559 ms
- ft/tests.py:204 TestAccountSettings.test_change_password · 479 ms
- apps/guides/content.py:112 render · 455 ms
- apps/orgs/tests.py:28 SignupTest.test_signing_up_creates_an_organization · 313 ms
- apps/api/tests.py:98 IngestStartEndpointTest.ingest_start · 312 ms
- ft/tests.py:160 TestAccountPages.test_signup · 252 ms
- ft/tests.py:199 TestAccountSettings.test_change_password · 252 ms
- apps/projects/urls.py:498 project_profile · 188 ms
- apps/orgs/views.py:33 org_shell · 180 ms
Most affected tests:
- ft/tests.py::TestAccountSettings::test_change_password
- apps/api/tests.py::ProfileUploadTest::test_missing_parts_mark_the_profile_incomplete
- apps/orgs/tests.py::SignupTest::test_signing_up_creates_an_organization
- ft/tests.py::TestAccountPages::test_signup
- apps/projects/tests.py::ProjectPagesTest::test_dashboard_filters
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_end_after_progress
- apps/api/tests.py::TestApiIndex::test_index
- apps/projects/tests.py::ProjectRunPage::test_project_with_runs_no_tests
Disable django-debug-toolbar in tests
django-debug-toolbar is installed in the test settings and costs 7.8s.
Details
Where:
- ft/tests.py:204 TestAccountSettings.test_change_password · 479 ms
- apps/guides/content.py:112 render · 455 ms
- apps/orgs/tests.py:28 SignupTest.test_signing_up_creates_an_organization · 302 ms
- ft/tests.py:160 TestAccountPages.test_signup · 252 ms
- ft/tests.py:199 TestAccountSettings.test_change_password · 252 ms
- apps/projects/urls.py:498 project_profile · 188 ms
- apps/orgs/views.py:33 org_shell · 180 ms
- apps/projects/models.py:18 get_or_create_numbered · 163 ms
- apps/projects/urls.py:49 find_project · 158 ms
- apps/api/urls.py:59 touch_token · 152 ms
Most affected tests:
- ft/tests.py::TestAccountSettings::test_change_password
- apps/api/tests.py::ProfileUploadTest::test_missing_parts_mark_the_profile_incomplete
- apps/orgs/tests.py::SignupTest::test_signing_up_creates_an_organization
- apps/projects/tests.py::ProjectPagesTest::test_dashboard_filters
- ft/tests.py::TestAccountPages::test_signup
- apps/api/tests.py::TestApiIndex::test_index
- apps/projects/tests.py::ProfilePagePaginationTest::test_slowest_tests_first_then_the_next_page
- apps/guides/tests.py::TestGuidePages::test_every_guide_renders
Make the test database server skip durability work
Tests spend 15.9s (59%) in the database. Test databases don't need to survive a crash, so the server can skip flushing to disk.
Details
Only affects crash safety of the throwaway test server; query behaviour is identical.
Where:
- apps/projects/models.py:466 Profile.save · 330 ms
- apps/projects/profiles.py:334 write_snapshots · 197 ms
- apps/api/tests.py:76 IngestStartEndpointTest.join_workers · 183 ms
- apps/projects/environments.py:63 get_or_create_environment · 177 ms
- apps/projects/tests.py:954 ProjectPagesTest.setUp · 169 ms
- apps/projects/models.py:18 get_or_create_numbered · 168 ms
- apps/orgs/views.py:33 org_shell · 167 ms
- apps/projects/urls.py:49 find_project · 158 ms
- apps/projects/profiles.py:479 write_perfs · 153 ms
- apps/api/urls.py:59 touch_token · 150 ms
Most affected tests:
- apps/api/tests.py::TestApiIndex::test_index
- apps/projects/tests.py::SeedDemoCommandTest::test_seed_demo
- apps/projects/tests.py::ProjectPagesTest::test_configure_page
- apps/projects/tests.py::ProjectPagesTest::test_dashboard_filters
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_start_progress_end
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_progress_before_start
- apps/api/tests.py::IngestStartEndpointTest::test_all_test_status_types
- apps/projects/tests.py::ProfilePagePaginationTest::test_slowest_tests_first_then_the_next_page
Repeated queries (N+1) in the code under test
27 tests run the same query 10+ times, e.g. 180x in test_seed_demo. N+1 queries slow the tests and production alike.
Details
This changes application code, so it speeds up production too; the tests stay as they are.
- 180x in test_seed_demo: SELECT "projects_test"."id", "projects_test"."name", "projects_test"."project_id", "projects_test"."slug", "projects_test"."date_last_run", "projects_test"."date_first_seen", "projects_test"."first_commit_id", "projects_test"."muted" FROM "projects_test" WHERE ("projects_test"."name" = %s AND "proj…
- 22x in test_dashboard_filters: SELECT "projects_environment"."id", "projects_environment"."project_id", "projects_environment"."name", "projects_environment"."kind", "projects_environment"."provider", "projects_environment"."details", "projects_environment"."date_first_seen", "projects_environment"."date_last_seen" FROM "project…
- 21x in test_configure_page: SELECT "projects_profile"."id", "projects_profile"."project_id", "projects_profile"."number", "projects_profile"."environment_id", "projects_profile"."session_id", "projects_profile"."run_id", "projects_profile"."commit_id", "projects_profile"."ingest_id", "projects_profile"."external_id", "project…
- 20x in test_index: SELECT "django_content_type"."model" AS "model" FROM "django_content_type" WHERE "django_content_type"."app_label" = %s
- 20x in test_daily_stats_count_a_profile_once_every_part_is_in: SELECT "projects_profilepart"."id", "projects_profilepart"."profile_id", "projects_profilepart"."index", "projects_profilepart"."count", "projects_profilepart"."checksum", "projects_profilepart"."status", "projects_profilepart"."error", "projects_profilepart"."tests_count", "projects_profilepart"."…
Most affected tests:
- apps/projects/tests.py::SeedDemoCommandTest::test_seed_demo
- apps/projects/tests.py::ProjectPagesTest::test_dashboard_filters
- apps/projects/tests.py::ProjectPagesTest::test_configure_page
- apps/api/tests.py::TestApiIndex::test_index
- apps/api/tests.py::ProfileUploadTest::test_daily_stats_count_a_profile_once_every_part_is_in
- apps/api/tests.py::IngestStartEndpointTest::test_all_test_status_types
- apps/api/tests.py::IngestStartEndpointTest::test_details_are_kept_for_failures_only
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_end_after_progress
Stop re-running migrations on every test run
Migrations take 3.2s per run, before the first test can start.
Details
CI should still build the database from scratch (no --reuse-db) so broken migrations are caught.
Where:
- apps/projects/migrations/0012_backfill_session_environments.py:30 backfill · 3 ms
- apps/projects/migrations/0014_backfill_session_counts.py:23 backfill · 3 ms
- apps/projects/migrations/0016_profile_parts.py:9 move_documents · 3 ms
- apps/projects/migrations/0012_backfill_session_environments.py:24 backfill · 1 ms
- apps/projects/migrations/0014_backfill_session_counts.py:15 backfill.<locals>.count · 1 ms
- apps/projects/migrations/0015_store_compressed_documents_as_is.py:12 external_storage · 1 ms
- apps/projects/migrations/0016_profile_parts.py:24 external_storage · 1 ms
- apps/projects/migrations/0022_backfill_organizations.py:48 forwards · 1 ms
- apps/projects/migrations/0022_backfill_organizations.py:69 forwards · 1 ms
- apps/projects/migrations/0025_backfill_slugs_and_numbers.py:28 forwards · 1 ms
Most affected tests:
- apps/api/tests.py::TestApiIndex::test_index
Use a fast password hasher in tests
2.4s (9% of test time) is spent hashing passwords. Slow hashing protects real passwords; in tests it only burns CPU.
Details
Only change the hasher in test settings. Tests that assert on a specific hash format need updating.
Where:
- ft/tests.py:204 TestAccountSettings.test_change_password · 470 ms
- apps/orgs/tests.py:194 SuperuserTest.test_superusers_can_open_any_project_but_dont_list_them · 438 ms
- ft/tests.py:231 TestAccountSettings.test_projects_only_lists_your_own_even_for_superusers · 264 ms
- apps/orgs/tests.py:28 SignupTest.test_signing_up_creates_an_organization · 255 ms
- ft/tests.py:199 TestAccountSettings.test_change_password · 250 ms
- ft/tests.py:160 TestAccountPages.test_signup · 241 ms
- ft/tests.py:214 TestAccountSettings.test_change_password · 234 ms
- ft/tests.py:176 TestAccountSettings.setUpTestData · 221 ms
Most affected tests:
- ft/tests.py::TestAccountSettings::test_change_password
- apps/orgs/tests.py::SuperuserTest::test_superusers_can_open_any_project_but_dont_list_them
- ft/tests.py::TestAccountSettings::test_projects_only_lists_your_own_even_for_superusers
- apps/orgs/tests.py::SignupTest::test_signing_up_creates_an_organization
- ft/tests.py::TestAccountPages::test_signup
pytest takes a long time before the first test runs
Startup takes 4.8s and collection 392ms on every run, even when you only run one test.
Use TestCase instead of TransactionTestCase
1.0s goes to flushing every table after tests in 11 TransactionTestCase / transaction=True / live_server tests.
Details
Tests that rely on commit behaviour, multiple connections or a live server still need a transactional test case.
Most affected tests:
- apps/api/tests.py::ProfileUploadLockTest::test_upload_while_a_part_is_being_processed
- apps/api/tests.py::ProfileUploadQueueTest::test_upload_is_processed_by_the_worker
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_multiple_sessions
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_progress_before_start
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_start_with_git
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_start_progress_end
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_valid
- apps/api/tests.py::IngestStartEndpointTest::test_all_test_status_types
Tests open new database connections over and over
Connecting to the database takes 968ms.
Details
Where:
- apps/api/tests.py:76 IngestStartEndpointTest.join_workers · 164 ms
- apps/api/tests.py:73 IngestStartEndpointTest.setUp · 99 ms
- apps/api/tasks.py:266 warm_reports · 61 ms
- apps/api/urls.py:72 api_request.<locals>.decorator.<locals>.wrapped_view · 48 ms
- apps/api/tests.py:306 IngestStartEndpointTest.test_details_are_kept_for_failures_only · 12 ms
- apps/api/tests.py:988 ProfileUploadQueueTest.test_upload_is_processed_by_the_worker · 12 ms
- apps/api/tasks.py:237 process_profile · 12 ms
- apps/api/tests.py:287 IngestStartEndpointTest.test_all_test_status_types · 10 ms
- apps/api/tests.py:235 IngestStartEndpointTest.test_ingest_progress_before_start · 10 ms
- apps/api/tests.py:928 ProfileUploadLockTest.setUp · 10 ms
Most affected tests:
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_progress_before_start
- apps/api/tests.py::IngestStartEndpointTest::test_all_test_status_types
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_start_progress_end
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_end_after_progress
- apps/api/tests.py::IngestStartEndpointTest::test_results_are_counted_and_the_payload_dropped
- apps/api/tests.py::ProfileUploadQueueTest::test_upload_is_processed_by_the_worker
- apps/api/tests.py::IngestStartEndpointTest::test_details_are_kept_for_failures_only
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_valid
Create shared test data in setUpTestData instead of setUp
setUp() runs before every test and takes 907ms in total (db 828ms, library 57ms, copying 10ms) in 14 classes: SettingsTest (3 tests), ProjectsPageTest (5 tests), ProjectEditPage (6 tests), ProjectDeletePage (4 tests).
Details
Since Django 3.2 attributes assigned in setUpTestData are deep-copied per test, so in-memory changes don't leak between tests. Keep objects a test modifies in the database (or re-fetches) as before.
Where:
- apps/projects/tests.py:954 ProjectPagesTest.setUp · 195 ms
- apps/api/tests.py:73 IngestStartEndpointTest.setUp · 149 ms
- apps/projects/tests.py:101 ProjectsPageTest.setUp · 81 ms
- apps/projects/tests.py:413 TestProjectTestPage.setUp · 59 ms
- apps/projects/tests.py:269 ProjectRunsPage.setUp · 55 ms
- apps/projects/tests.py:338 ProjectTestsPage.setUp · 53 ms
- ft/tests.py:180 TestAccountSettings.setUp · 53 ms
- apps/projects/tests.py:143 ProjectEditPage.setUp · 50 ms
- apps/projects/tests.py:188 ProjectDeletePage.setUp · 41 ms
- apps/projects/tests.py:219 ProjectCreatePage.setUp · 39 ms
Most affected tests:
- apps/projects/tests.py::ProjectsPageTest::test_other_peoples_project
- apps/projects/tests.py::TestProjectTestPage::test_other_peoples_project
- apps/projects/tests.py::ProjectTestsPage::test_project_with_no_tests
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_valid
- ft/tests.py::TestAccountSettings::test_connections
- apps/projects/tests.py::ProjectsPageTest::test_not_logged_in
- apps/projects/tests.py::UnstorableCharactersTest::test_test_page_renders_a_stored_lone_surrogate
- apps/api/tests.py::IngestStartEndpointTest::test_all_test_status_types
Tests
1–200 of 253, slowest first · click a column to sort this pageMemory
The test process peaked at 211 MBSlowest fixtures
Exact setup time across the session| Fixture | Scope | Calls | Total |
|---|---|---|---|
| _django_setup_unittest | class | 54 | 3.41 s |
| django_db_setup | session | 1 | 3.39 s |
| _unittest_setUpClass_fixture_ProjectPagesTest | class | 1 | 256 ms |
| _unittest_setUpClass_fixture_TestAccountSettings | class | 1 | 239 ms |
| _unittest_setUpClass_fixture_ProfilePagePaginationTest | class | 1 | 202 ms |
| _unittest_setUpClass_fixture_McpTest | class | 1 | 171 ms |
| _unittest_setUpClass_fixture_AnalyticsTest | class | 1 | 165 ms |
| _unittest_setUpClass_fixture_RealProfileDocumentTest | class | 1 | 127 ms |
| _unittest_setUpClass_fixture_MemoryTest | class | 1 | 84 ms |
| _unittest_setUpClass_fixture_StorageTest | class | 1 | 78 ms |
| _unittest_setUpClass_fixture_FlakyReportTest | class | 1 | 64 ms |
| _unittest_setUpClass_fixture_LegacyUrlTest | class | 1 | 59 ms |
| _unittest_setUpClass_fixture_UnstorableCharactersTest | class | 1 | 50 ms |
| _unittest_setUpClass_fixture_FlakyReportCacheTest | class | 1 | 49 ms |
| _unittest_setUpClass_fixture_SuperuserTest | class | 1 | 22 ms |