Zero-configuration Docker-based testing for Blik360.
# Run all tests
./test.sh
# Run specific app tests
./test.sh accounts
./test.sh questionnaires
# Run specific test class
./test.sh accounts.tests.UserInvitationTestCase
# Run with verbose output
./test.sh -v
# Keep database between runs (faster)
./test.sh --keepdbThe test setup includes:
- PostgreSQL database (temporary, in-memory)
- Mailpit for email testing (http://localhost:8125)
- Sample data fixtures:
- Test organization
- Admin and manager users
- 3 test reviewees
- Default questionnaire
- Sample review cycle with tokens
All emails sent during tests go to Mailpit:
# Open Mailpit UI
./test.sh mailpitThen visit http://localhost:8125 to see all sent emails.
Note: Test environment uses non-standard ports to avoid conflicts:
- Mailpit Web UI:
8125(instead of 8025) - Mailpit SMTP:
1125(instead of 1025)
Tests use factory_boy to generate data programmatically (not JSON fixtures).
Key factories available:
OrganizationFactory- Create test organizationsUserFactory/AdminUserFactory- Create usersRevieweeFactory- Create revieweesQuestionnaireFactory- Create questionnairesQuestionSectionFactory/QuestionFactory- Create questionsReviewCycleFactory- Create review cyclesReviewerTokenFactory- Create reviewer tokens
| Username | Password | Role | |
|---|---|---|---|
| admin | admin@test.local | admin123 | Superuser |
| manager | manager@test.local | - | Regular user |
- John Developer (john.dev@test.local) - Senior Software Engineer
- Jane Manager (jane.manager@test.local) - Engineering Manager
- Bob Junior (bob.junior@test.local) - Junior Developer
- ✓ Fixture loading
- ✓ Questionnaire sections
- ✓ Questions
- ✓ Invitation token generation
- ✓ Token uniqueness
- ✓ Claiming invite links
- ✓ Reviewer token access
- ✓ Assigning emails to tokens
- ✓ Sending reviewer invitations
- ✓ Preventing resend to completed reviews
- ✓ Dashboard access
- ✓ Reviewee listing
- ✓ Creating invitations
- ✓ Token uniqueness
- ✓ Expiration validation
- ✓ Acceptance validation
- ✓ Manual report generation
- ○ Auto-generation (depends on signals)
- ✓ Listing reviewees
- ✓ Creating reviewees
- ✓ Deactivating reviewees
# Open Django shell in test environment
./test.sh shell
# Then in the shell:
python manage.py shell
python manage.py migrate
python manage.py loaddata core/fixtures/test_data.json# Remove all test containers and volumes
./test.sh clean# Just start services without running tests
./test.sh setupfrom django.test import TestCase
from core.factories import OrganizationFactory, UserFactory
from accounts.factories import RevieweeFactory
class MyTestCase(TestCase):
def setUp(self):
# Create test data with factories
self.org = OrganizationFactory(name='Test Org')
self.user = UserFactory()
self.reviewee = RevieweeFactory(organization=self.org)
def test_something(self):
# Your test here
self.assertEqual(self.org.name, 'Test Org')
self.assertIsNotNone(self.reviewee.organization)Benefits of factories over JSON fixtures:
- Type-safe - Catches model changes immediately
- Flexible - Override any field easily
- No maintenance - Auto-adapts to model changes
- Readable - Clear what data is being created
Create test data programmatically:
from core.factories import OrganizationFactory, UserFactory
from accounts.factories import RevieweeFactory
from questionnaires.factories import QuestionnaireFactory
# Create organization
org = OrganizationFactory(name='Acme Corp')
# Create user
user = UserFactory(username='testuser')
user.set_password('password123')
user.save()
# Create reviewee
reviewee = RevieweeFactory(
organization=org,
name='John Doe',
email='john@acme.com'
)
# Create questionnaire with questions
questionnaire = QuestionnaireFactory(organization=org)from django.core import mail
def test_send_email(self):
# Send email
send_email(
subject='Test',
message='Body',
recipient_list=['test@example.com']
)
# Check email was sent
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, 'Test')
# Or check in Mailpit UI at http://localhost:8125mail.outbox only fills when the organization has no smtp_host: organization
SMTP settings take priority over EMAIL_BACKEND, so an org configured with a
host will try to open a real connection. Factories leave smtp_host empty, so
this works by default — but if you set one, patch send_email instead.
- Logging in: use
self.client.force_login(user).client.login()raisesAxesBackendRequestParameterRequired— django-axes needs a request object, which the test client'slogin()does not pass. - Your
.envleaks into tests. It is loaded intoos.environ, so anything reading env vars (e.g. which org settings are environment-managed) sees your machine's values. Clear them withpatch.dict(os.environ, ..., clear=True)— seecore/test_env_locked_settings.py. - Signals that use
transaction.on_commit(webhooks) never fire inside aTestCase, whose transaction is rolled back. Wrap the write inwith self.captureOnCommitCallbacks(execute=True):. - Creating a
UserProfileauto-creates aRevieweefor that user. Assert on membership (assertIn(email, emails)) rather than exact row counts, which also drift when new orgs get template questionnaires cloned in.
def test_invite_link(self):
cycle = ReviewCycle.objects.get(pk=1)
# Get invitation URL
url = reverse('reviews:claim_token', kwargs={
'invitation_token': cycle.invitation_token_peer
})
# Claim the invite
response = self.client.get(url)
# Should create reviewer token
self.assertEqual(response.status_code, 200)The test script is designed for CI/CD:
# GitHub Actions example
- name: Run tests
run: |
./test.sh --verbosity=2# Clean and restart
./test.sh clean
./test.sh setupCheck if services are running:
docker compose -f docker-compose.test.yml psdocker compose -f docker-compose.test.yml logs -fTest environment uses non-standard ports to minimize conflicts:
- Mailpit Web UI: 8125 (not 8025)
- Mailpit SMTP: 1125 (not 1025)
- PostgreSQL: 5432 (only accessible internally, not exposed)
If you still have conflicts:
# Stop conflicting services
docker compose -f docker-compose.test.yml down
# Or check what's using the port
lsof -i :8125
lsof -i :1125-
Use
--keepdbfor repeated test runs:./test.sh --keepdb
-
Run specific tests instead of full suite:
./test.sh accounts.tests.UserInvitationTestCase
-
Database is in-memory (tmpfs) for speed
Test environment uses .env.test:
DATABASE_TYPE=postgresDATABASE_NAME=blik_testEMAIL_HOST=mailpitDEBUG=True- All security features relaxed for testing
For manual testing with real data:
# Start test environment
./test.sh setup
# Open shell
./test.sh shell
# Create test data using Django shell
python manage.py shell
# In shell:
from core.factories import *
from accounts.factories import *
from questionnaires.factories import *
org = OrganizationFactory(name='Test Org')
user = UserFactory(username='admin', is_superuser=True)
user.set_password('admin')
user.save()
reviewee = RevieweeFactory(organization=org)
# Create superuser
python manage.py createsuperuser
# Run dev server
python manage.py runserver 0.0.0.0:8000Then access at http://localhost:8000 and check emails at http://localhost:8125.