Passed Run of Oct 26, 23:42
Where the time goes
Test time by category- Database7.20 s
- Libraries2.89 s
- DB schema1.78 s
- Password hashing1.24 s
- Migrations988 ms
- Templates697 ms
- Imports328 ms
- App code174 ms
- Serialization138 ms
- Unsampled109 ms
- pytest77 ms
- Deep copies31 ms
- Factories20 ms
- Test code19 ms
- Waiting9 ms
- Cache3 ms
- Logging3 ms
- Mocking0.94 ms
Session timeline
Fix next
Ranked by the time each fix saves per runUse plain static file storage in tests
Static file storage/manifest handling costs 6.7s.
Details
Where:
- apps/api/tests.py:487 ProfileUploadTest.upload · 363 ms
- apps/mcp/tests.py:67 McpTest.post · 276 ms
- apps/projects/urls.py:498 project_profile · 271 ms
- ft/tests.py:204 TestAccountSettings.test_change_password · 261 ms
- apps/guides/content.py:112 render · 240 ms
- apps/orgs/tests.py:28 SignupTest.test_signing_up_creates_an_organization · 185 ms
- ft/tests.py:160 TestAccountPages.test_signup · 153 ms
- apps/orgs/tests.py:92 MembersTest.test_owner_invites_someone_who_signs_up · 153 ms
- apps/projects/tests.py:425 TestProjectTestPage.test_other_peoples_project · 146 ms
- ft/tests.py:199 TestAccountSettings.test_change_password · 130 ms
Most affected tests:
- ft/tests.py::TestAccountSettings::test_change_password
- apps/api/tests.py::ProfileUploadTest::test_missing_parts_mark_the_profile_incomplete
- apps/projects/tests.py::ProfilePagePaginationTest::test_slowest_tests_first_then_the_next_page
- apps/orgs/tests.py::SignupTest::test_signing_up_creates_an_organization
- apps/orgs/tests.py::MembersTest::test_owner_invites_someone_who_signs_up
- apps/api/tests.py::TestApiIndex::test_index
- ft/tests.py::TestAccountPages::test_signup
- apps/projects/tests.py::ProjectPagesTest::test_dashboard_filters
Disable django-debug-toolbar in tests
django-debug-toolbar is installed in the test settings and costs 4.4s.
Details
Where:
- apps/projects/urls.py:498 project_profile · 271 ms
- ft/tests.py:204 TestAccountSettings.test_change_password · 261 ms
- apps/guides/content.py:112 render · 240 ms
- apps/orgs/tests.py:28 SignupTest.test_signing_up_creates_an_organization · 184 ms
- ft/tests.py:160 TestAccountPages.test_signup · 153 ms
- ft/tests.py:199 TestAccountSettings.test_change_password · 130 ms
- ft/urls.py:151 <module> · 130 ms
- apps/orgs/views.py:33 org_shell · 106 ms
- apps/orgs/models.py:65 Organization.is_owner · 100 ms
- apps/api/urls.py:72 api_request.<locals>.decorator.<locals>.wrapped_view · 96 ms
Most affected tests:
- ft/tests.py::TestAccountSettings::test_change_password
- apps/api/tests.py::ProfileUploadTest::test_missing_parts_mark_the_profile_incomplete
- apps/projects/tests.py::ProfilePagePaginationTest::test_slowest_tests_first_then_the_next_page
- apps/orgs/tests.py::SignupTest::test_signing_up_creates_an_organization
- apps/api/tests.py::TestApiIndex::test_index
- ft/tests.py::TestAccountPages::test_signup
- apps/projects/tests.py::ProjectPagesTest::test_dashboard_filters
- apps/api/tests.py::ProfileUploadTest::test_upload_adds_migrations_per_worker_insight
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
Make the test database server skip durability work
Tests spend 10.0s (64%) 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 · 197 ms
- apps/projects/profiles.py:334 write_snapshots · 150 ms
- apps/projects/tests.py:954 ProjectPagesTest.setUp · 143 ms
- apps/api/tests.py:76 IngestStartEndpointTest.join_workers · 108 ms
- apps/projects/models.py:35 next_number · 107 ms
- apps/projects/profiles.py:379 claim_part · 104 ms
- apps/projects/environments.py:63 get_or_create_environment · 103 ms
- apps/projects/models.py:230 TestManager.upsert · 102 ms
- apps/orgs/views.py:33 org_shell · 101 ms
- apps/projects/rollups.py:88 add_perfs · 100 ms
Most affected tests:
- apps/api/tests.py::TestApiIndex::test_index
- apps/projects/tests.py::SeedDemoCommandTest::test_seed_demo
- 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_end_after_progress
- apps/api/tests.py::IngestStartEndpointTest::test_results_are_counted_and_the_payload_dropped
- apps/projects/tests.py::ProjectPagesTest::test_configure_page
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_start_progress_end
pytest takes a long time before the first test runs
Startup takes 3.3s and collection 185ms on every run, even when you only run one test.
Use a fast password hasher in tests
1.2s (8% 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 · 258 ms
- ft/tests.py:160 TestAccountPages.test_signup · 150 ms
- ft/tests.py:231 TestAccountSettings.test_projects_only_lists_your_own_even_for_superusers · 148 ms
- apps/orgs/tests.py:194 SuperuserTest.test_superusers_can_open_any_project_but_dont_list_them · 144 ms
- apps/orgs/tests.py:28 SignupTest.test_signing_up_creates_an_organization · 143 ms
- ft/tests.py:176 TestAccountSettings.setUpTestData · 131 ms
- ft/tests.py:214 TestAccountSettings.test_change_password · 129 ms
- ft/tests.py:199 TestAccountSettings.test_change_password · 128 ms
- ft/tests.py:47 TestProjectsHome.test_user_logged_in_with_multiple_projects · 2 ms
- apps/orgs/tests.py:52 OrganizationTestCase.setUpTestData · 1 ms
Most affected tests:
- ft/tests.py::TestAccountSettings::test_change_password
- ft/tests.py::TestAccountPages::test_signup
- ft/tests.py::TestAccountSettings::test_projects_only_lists_your_own_even_for_superusers
- apps/orgs/tests.py::SuperuserTest::test_superusers_can_open_any_project_but_dont_list_them
- apps/orgs/tests.py::SignupTest::test_signing_up_creates_an_organization
- ft/tests.py::TestProjectsHome::test_user_logged_in_with_multiple_projects
- apps/orgs/tests.py::AccessTest::test_members_see_every_project_of_the_organization
- apps/projects/tests.py::ProjectCreatePage::test_first_project_is_onboarding
Use TestCase instead of TransactionTestCase
759ms 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::ProfileUploadQueueTest::test_upload_is_processed_by_the_worker
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_start_progress_end
- 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_details_are_kept_for_failures_only
- apps/api/tests.py::ProfileUploadLockTest::test_upload_while_a_part_is_being_processed
- apps/api/tests.py::IngestStartEndpointTest::test_all_test_status_types
Tests open new database connections over and over
Connecting to the database takes 631ms.
Details
Where:
- apps/api/tests.py:76 IngestStartEndpointTest.join_workers · 91 ms
- apps/api/tests.py:73 IngestStartEndpointTest.setUp · 63 ms
- apps/api/tasks.py:266 warm_reports · 37 ms
- apps/api/urls.py:72 api_request.<locals>.decorator.<locals>.wrapped_view · 33 ms
- apps/api/tests.py:306 IngestStartEndpointTest.test_details_are_kept_for_failures_only · 8 ms
- apps/api/tests.py:212 IngestStartEndpointTest.test_ingest_start_progress_end · 7 ms
- apps/api/tests.py:928 ProfileUploadLockTest.setUp · 7 ms
- apps/api/tests.py:235 IngestStartEndpointTest.test_ingest_progress_before_start · 7 ms
- apps/api/tasks.py:237 process_profile · 6 ms
- apps/api/tests.py:975 ProfileUploadQueueTest.setUp · 6 ms
Most affected tests:
- apps/api/tests.py::IngestStartEndpointTest::test_results_are_counted_and_the_payload_dropped
- apps/api/tests.py::IngestStartEndpointTest::test_all_test_status_types
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_progress_before_start
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_start_progress_end
- apps/api/tests.py::IngestStartEndpointTest::test_ingest_end_after_progress
- 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/projects/tests.py::ProfilePagePaginationTest::test_slowest_tests_first_then_the_next_page
Create shared test data in setUpTestData instead of setUp
setUp() runs before every test and takes 568ms in total (db 531ms, library 33ms, factories 4ms) 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 · 153 ms
- apps/api/tests.py:73 IngestStartEndpointTest.setUp · 98 ms
- apps/projects/tests.py:143 ProjectEditPage.setUp · 38 ms
- apps/projects/tests.py:1413 MemoryTest.setUp · 37 ms
- ft/tests.py:180 TestAccountSettings.setUp · 36 ms
- apps/projects/tests.py:101 ProjectsPageTest.setUp · 32 ms
- apps/projects/tests.py:413 TestProjectTestPage.setUp · 27 ms
- apps/projects/tests.py:338 ProjectTestsPage.setUp · 24 ms
- apps/projects/tests.py:269 ProjectRunsPage.setUp · 23 ms
- apps/projects/tests.py:188 ProjectDeletePage.setUp · 23 ms
Most affected tests:
- apps/api/tests.py::IngestStartEndpointTest::test_results_are_counted_and_the_payload_dropped
- apps/projects/tests.py::ProjectTestsPage::test_project_with_no_tests
- apps/projects/tests.py::ProjectEditPage::test_slug_unique_in_organization
- apps/projects/tests.py::ProjectsPageTest::test_other_peoples_project
- ft/tests.py::TestAccountSettings::test_set_password_for_github_users
- apps/projects/tests.py::ProjectDeletePage::test_not_logged_in
- apps/projects/tests.py::ProjectPagesTest::test_test_page_without_profiles
- 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 215 MBSlowest fixtures
Exact setup time across the session| Fixture | Scope | Calls | Total |
|---|---|---|---|
| _django_setup_unittest | class | 54 | 2.04 s |
| django_db_setup | session | 1 | 2.02 s |
| _unittest_setUpClass_fixture_ProjectPagesTest | class | 1 | 168 ms |
| _unittest_setUpClass_fixture_ProfilePagePaginationTest | class | 1 | 147 ms |
| _unittest_setUpClass_fixture_TestAccountSettings | class | 1 | 138 ms |
| _unittest_setUpClass_fixture_McpTest | class | 1 | 112 ms |
| _unittest_setUpClass_fixture_AnalyticsTest | class | 1 | 106 ms |
| _unittest_setUpClass_fixture_RealProfileDocumentTest | class | 1 | 78 ms |
| _unittest_setUpClass_fixture_MemoryTest | class | 1 | 55 ms |
| _unittest_setUpClass_fixture_StorageTest | class | 1 | 49 ms |
| _unittest_setUpClass_fixture_FlakyReportCacheTest | class | 1 | 45 ms |
| _unittest_setUpClass_fixture_FlakyReportTest | class | 1 | 41 ms |
| _unittest_setUpClass_fixture_UnstorableCharactersTest | class | 1 | 37 ms |
| _unittest_setUpClass_fixture_LegacyUrlTest | class | 1 | 37 ms |
| _unittest_setUpClass_fixture_TestProjectTestPage | class | 1 | 12 ms |