Testing philosophy: Test-Driven Development (TDD)
We follow Test-Driven Development (TDD) for all microservices, including the Address API. This means:- Write tests first: Before implementing a feature, write tests that define the expected behavior
- Watch tests fail: Run the tests and verify they fail (proving they’re testing something)
- Implement the feature: Write the minimum code needed to make the tests pass
- Refactor: Clean up the code while keeping tests green
Why TDD for microservices?
- Clear requirements: Tests document what the API should do
- Confidence in changes: Refactor without fear of breaking things
- Better design: Writing tests first leads to more testable, modular code
- Regression prevention: Bugs become test cases that prevent future regressions
- Integration safety: Microservices have many integration points - tests catch breaking changes
TDD workflow example
Test structure
Running tests
Run all tests
Run integration tests only
Run unit tests only
Using the CLI command
Integration tests
Integration tests use testcontainers-go to spin up a real PostgreSQL database in Docker.Prerequisites
- Docker must be running
GOOGLE_GEOCODING_API_KEYenvironment variable must be set
How integration tests work
- Container startup: Testcontainers starts a PostgreSQL 15 container
- Migration: Atlas applies all migrations to the test database
- Test execution: Tests run against the real database
- Cleanup: Container is automatically destroyed after tests complete
Test coverage
| Test file | Coverage |
|---|---|
authorization_tests.go | API key authentication and role-based access control |
geoencode_tests.go | Geocoding endpoint with caching and Google API integration |
ingestion_tests.go | ISO 3166 content ingestion with upsert logic |
Example integration test
Unit tests
Unit tests test individual functions without external dependencies.Example unit test
Test helpers
Thetest_helpers.go file provides utilities for integration tests:
Running tests in CI
Tests run automatically on every pull request via GitHub Actions.PR checks workflow
Testing practices
We follow these testing practices for the Address API:1. Test-Driven Development (TDD)
- Write tests before implementation
- Start with the simplest test case
- Add more complex scenarios incrementally
- Refactor only when tests are green
2. Integration over unit tests
For microservices, we prioritize integration tests over unit tests because:- They test the full request/response cycle
- They catch integration issues with databases and external APIs
- They provide more confidence in production behavior
- They’re closer to how the API is actually used
3. Test real dependencies
- Use testcontainers for PostgreSQL (not mocks)
- Use real Google Geocoding API (with test key)
- Test actual HTTP requests and responses
- Verify database state after operations
4. Test error scenarios
Don’t just test happy paths:- Missing required fields
- Invalid data formats
- Database failures
- External API failures
- Authorization failures
5. Keep tests independent
- Each test should set up its own data
- Don’t rely on test execution order
- Clean up after tests (testcontainers handles this)