Testing Guide
Last updated: 2026-10-12
Comprehensive testing documentation for Filament Address Pro package.
Table of Contents
- Prerequisites
- Overview
- Quick Start
- Test Architecture
- Test Categories
- Running Tests
- Test Coverage
- Writing Tests
- CI/CD Integration
- Troubleshooting
Prerequisites
The test suite runs from the package directory, not from inside your Laravel application. When you install the package via Composer, the dev dependencies (Pest, Testbench, Mockery) are not installed. You need to install them first.
Step 1 — Install dev dependencies
cd vendor/viewflex/filament-address-pro
composer installStep 2 — Configure the test database connection
cp phpunit.xml.dist phpunit.xml
# Edit phpunit.xml and set DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORDStep 3 — Create and seed the test database
Integration, Feature, Smoke, and Performance tests require a pre-seeded MySQL database. Unit tests do not — skip this step if you only want to run Unit tests.
mysql -u root -e "CREATE DATABASE filament_addresses_test;"
vendor/bin/testbench migrate --force
vendor/bin/testbench db:seed --force \
--class="Viewflex\FilamentAddress\Database\Seeders\CountriesDomainSeeder"Why MySQL? The seeded country data (256 countries, 17K+ subdivisions) makes SQLite in-memory impractically slow. MySQL with pre-seeded data and
DatabaseTransactionsrollback is ~315x faster.
Running unit tests only (no database needed)
cd vendor/viewflex/filament-address-pro
composer install
vendor/bin/pest --testsuite=UnitOverview
The Filament Address Pro package has 1,308 comprehensive tests across 5 categories:
- Pure Unit Tests (252 tests): No Laravel dependencies, instant feedback
- Integration Tests (868 tests): Laravel + Database with transactions - includes authorization and pre-release validation
- Feature Tests (72 tests): Full-stack HTTP integration
- Smoke Tests (73 tests): Quick health checks (passing + a few skipped for API keys)
- Performance Tests (37 tests): Timing benchmarks and baselines
Current Status: 1,308 tests passing, 12 skipped (expected)
Total Test Execution Time: ~3 minutes (175 seconds)
Quick Start
# Run all tests
composer test
# or: vendor/bin/pest
# Run specific test suite
vendor/bin/pest --testsuite=Unit
vendor/bin/pest --testsuite=Integration
vendor/bin/pest --testsuite=Feature
vendor/bin/pest --testsuite=Smoke
vendor/bin/pest --testsuite=Performance
# Run specific groups
vendor/bin/pest --group=smoke
vendor/bin/pest --group=performance
vendor/bin/pest --group=pre-release
# Run specific test file
vendor/bin/pest tests/Unit/Extractors/JapaneseAddressExtractorTest.php
# Run with coverage (requires Xdebug)
vendor/bin/pest --coverageTest Architecture
Directory Structure
tests/
├── Unit/ # Pure unit tests (no Laravel)
│ ├── Extractors/ # Address component extractors
│ ├── Services/ # Service layer logic
│ └── Utilities/ # Helper utilities
├── Integration/ # Laravel + Database tests
│ ├── Models/ # Model behavior
│ ├── Services/ # Service integration
│ └── Configuration/ # Config validation
├── Feature/ # Full-stack HTTP tests
│ └── Services/ # API integration
├── Smoke/ # Quick health checks
│ ├── PackageHealthTest.php
│ ├── CountryFixturesSmokeTest.php
│ ├── ExtractorsSmokeTest.php
│ ├── ServiceHealthSmokeTest.php
│ └── DataIntegritySmokeTest.php
├── Performance/ # Performance benchmarks
│ ├── GeocodingPerformanceTest.php
│ ├── SubdivisionMatchingPerformanceTest.php
│ ├── ExtractorPerformanceTest.php
│ └── FixtureParsingPerformanceTest.php
└── Support/ # Test utilities
└── TestAddressParser.phpThree-Tier Testing Strategy
Pure Unit Tests - Fast, isolated, no dependencies
- Instant feedback (< 0.2s)
- Test business logic in isolation
- No database, no HTTP, no external services
Integration Tests - Laravel features + Database
- Fast with database transactions (< 5s)
- Test Laravel integration (models, services, events)
- Use
filament_addresses_testMySQL database
Feature Tests - Full stack integration
- External API calls (geocoding, verification)
- End-to-end workflows
- Slower but comprehensive
Test Categories
1. Pure Unit Tests (112 tests)
Location: tests/Unit/Speed: ~0.14 seconds Database: None Purpose: Test business logic in isolation
What's Tested:
- Address component extractors (Default, Japanese, Korean, ConfigBased)
- Postal code validation
- Address formatting logic
- Cache key generation
- Utility functions
Example:
test('japanese extractor identifies address numbers correctly', function () {
$extractor = new JapaneseAddressExtractor();
expect($extractor->isAddressNumber('4-chōme-2-8'))->toBeTrue()
->and($extractor->isAddressNumber('Tokyo Tower'))->toBeFalse();
});Run: vendor/bin/pest --testsuite=Unit
2. Integration Tests (521 tests)
Location: tests/Integration/Speed: ~3-5 seconds Database: filament_addresses_test (MySQL) Purpose: Test Laravel integration with database
What's Tested:
- Model relationships and scopes
- Service layer with database
- Configuration consistency
- Observers and events
- Database queries and performance
- Subdivision matching
- Quality scoring
Key Features:
- Uses database transactions (fast rollback)
- Pre-seeded test database (315x faster than SQLite)
- Tests real Laravel features
Example:
test('country has many subdivisions relationship', function () {
$us = Country::where('country_code', 'US')->first();
$subdivisions = $us->activeSubdivisions()->get();
expect($subdivisions)->toBeInstanceOf(Collection::class)
->and($subdivisions->count())->toBeGreaterThan(50);
});Run: vendor/bin/pest --testsuite=Integration
3. Feature Tests (52 tests)
Location: tests/Feature/Speed: Variable (depends on API calls) Database: Test database Purpose: Test full-stack workflows with external services
What's Tested:
- International address testing (19 tests) - 46 countries covered
- Geocoding service (15 tests)
- Address verification (USPS, Google)
- Complete address processing workflows
- Import/export functionality
Example:
test('geocoding service returns valid coordinates', function () {
$service = app(GeocodingService::class);
$result = $service->geocode('1600 Pennsylvania Avenue NW, Washington, DC');
expect($result)->not->toBeNull()
->and($result['lat'])->toBeCloseTo(38.8977, 0.01)
->and($result['lng'])->toBeCloseTo(-77.0365, 0.01);
})->group('api');Run: vendor/bin/pest --testsuite=Feature
4. Smoke Tests (71 tests)
Location: tests/Smoke/Speed: ~7.5 seconds Purpose: Quick health checks for critical functionality
Current Status: Passing (a few skipped when API keys not configured - expected)
What's Tested:
- Package health and configuration
- Country fixtures integrity
- Extractor functionality
- Service health and instantiation
- Data integrity checks
- Component health
- API connectivity (skipped without API keys)
Categories:
- Core Health (smoke): Database, seeding, formatting
- API Connectivity (smoke-api): External services (skipped without API keys)
- Components (smoke-components): Filament components and service health
When to Run:
- Before every release
- Daily in CI/CD
- After database migrations
- After configuration changes
- When debugging package setup
Example:
test('all 46 country fixture files exist', function () {
$parser = new TestAddressParser();
$countries = $parser->getAllCountries();
expect(count($countries))->toBeGreaterThanOrEqual(46);
})->group('smoke', 'smoke-fixtures');Run:
# All smoke tests
vendor/bin/pest --group=smoke
# Specific categories
vendor/bin/pest --group=smoke-fixtures
vendor/bin/pest --group=smoke-extractors
vendor/bin/pest --group=smoke-services
vendor/bin/pest --group=smoke-data
# Exclude API tests (for CI)
vendor/bin/pest --group=smoke --exclude-group=smoke-apiDocumentation: tests/Smoke/README.md
5. Pre-Release Validation (5 tests)
Location: tests/Integration/PreReleaseCountryValidationTest.php (part of Integration suite) Speed: Included in Integration tests (~3 minutes total) Purpose: Ensure all 256 countries work before release
What's Tested:
- All 256 countries can geocode without errors (5 comprehensive tests)
- 245 countries successful, 11 appropriately skipped (uninhabited territories)
- 154 countries can extract subdivisions
- 245 countries can process full workflow
- Database properly seeded
- Capital addresses available
Results:
- ✅ All 256 countries validated successfully
- ✅ 0 failures
- ✅ Comprehensive assertions for each country
When to Run:
- Before every package release
- After major configuration changes
- When adding new countries
Run:
vendor/bin/pest --group=pre-releaseThese tests validate the package against all 256 countries to ensure zero critical failures before release.
Running Tests
By Test Suite
# Pure unit tests (fastest)
vendor/bin/pest --testsuite=Unit
# Integration tests
vendor/bin/pest --testsuite=Integration
# Feature tests (may hit APIs)
vendor/bin/pest --testsuite=Feature
# Smoke tests (health checks)
vendor/bin/pest --testsuite=Smoke
# Performance benchmarks
vendor/bin/pest --testsuite=PerformanceBy Group
# Smoke tests
vendor/bin/pest --group=smoke
# Performance tests
vendor/bin/pest --group=performance
# Pre-release validation
vendor/bin/pest --group=pre-release
# International addresses
vendor/bin/pest --group=international
# API-dependent tests (skip in CI)
vendor/bin/pest --exclude-group=apiBy File
# Specific test file
vendor/bin/pest tests/Unit/Extractors/JapaneseAddressExtractorTest.php
# Specific test method
vendor/bin/pest --filter="japanese extractor identifies address numbers"Daily Development Workflow
# Fast feedback loop (< 5s)
vendor/bin/pest --testsuite=Unit --testsuite=Integration
# Before commit (< 15s)
vendor/bin/pest --exclude-group=api,pre-release
# Before push (< 2 min)
vendor/bin/pest --group=smoke,performance
# Before release (< 5 min)
composer testTest Coverage
Current Coverage
Total: 1062 tests passing, 10 skipped
| Category | Tests | Speed | Status |
|---|---|---|---|
| Pure Unit | 252 | ~0.14s | All passing |
| Integration | 868 | ~3-5s | All passing, 4 skipped (includes pre-release) |
| Feature | 72 | Variable | All passing (46 countries) |
| Smoke | 73 | ~7.5s | Passing, 6 skipped (API keys) |
| Performance | 37 | ~0.74s | All passing, 2 skipped (expected) |
| Total | 1,308 | ~4.5min | 100% Success |
Coverage by Feature
- ✅ Address Models: 100% covered
- ✅ Country/Subdivision Models: 100% covered
- ✅ Geocoding Service: 100% covered
- ✅ Address Verification: 100% covered
- ✅ Bulk Operations: 100% covered
- ✅ Quality Scoring: 100% covered
- ✅ Import/Export: 100% covered
- ✅ Extractors: 100% covered (Default, Japanese, Korean, ConfigBased)
- ✅ International Support: 46 countries with fixture tests
- ✅ All Countries: 256 countries validated for basic functionality
Writing Tests
Local Setup for Contributors
Tests use Orchestra\Testbench and run standalone from the package directory. One-time setup:
# 1. Copy the distribution config and add your local DB credentials
cp phpunit.xml.dist phpunit.xml
# Edit phpunit.xml: set DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD
# 2. Create and seed the test database
mysql -u root -e "CREATE DATABASE filament_addresses_test;"
vendor/bin/testbench migrate --force
vendor/bin/testbench db:seed --force \
--class="Viewflex\FilamentAddress\Database\Seeders\CountriesDomainSeeder"
# 3. Run tests
composer test
# or: vendor/bin/pestThe phpunit.xml file is gitignored; only phpunit.xml.dist is committed.
Test Structure
All tests use Pest PHP syntax:
use Viewflex\FilamentAddress\Tests\TestCase;
uses(TestCase::class);
test('description of what is being tested', function () {
// Arrange
$input = 'test data';
// Act
$result = someFunction($input);
// Assert
expect($result)->toBe('expected output');
})->group('category');Unit Test Example
test('postal code validation works correctly', function () {
expect(CountryService::validatePostalCode('\d{5}', '12345'))->toBeTrue()
->and(CountryService::validatePostalCode('\d{5}', 'ABC'))->toBeFalse();
})->group('unit');Integration Test Example
test('country has active subdivisions', function () {
$country = Country::factory()->create();
$subdivision = CountrySubdivision::factory()->create([
'country_id' => $country->id,
'is_active' => true,
]);
$active = $country->activeSubdivisions()->get();
expect($active)->toHaveCount(1)
->and($active->first()->id)->toBe($subdivision->id);
})->group('integration');Feature Test Example
test('address processing completes full workflow', function () {
$place = [
'formatted_address' => '1600 Pennsylvania Avenue NW, Washington, DC 20500',
'lat' => 38.8977,
'lng' => -77.0365,
'place_id' => 'test-place-id',
];
$result = AddressProcessingService::processFromPlace($place, 'US');
expect($result)->toHaveKey('address_line_1')
->and($result)->toHaveKey('city')
->and($result)->toHaveKey('state')
->and($result)->toHaveKey('postal_code');
})->group('feature');Smoke Test Example
test('geocoding service can be instantiated', function () {
$service = app(GeocodingService::class);
expect($service)->toBeInstanceOf(GeocodingService::class);
})->group('smoke', 'smoke-services');Performance Test Example
test('operation is fast', function () {
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
// Perform operation
}
$duration = microtime(true) - $start;
expect($duration)->toBeLessThan(0.1,
"Operation: {$duration}s for 1000 iterations");
})->group('performance');CI/CD Integration
GitHub Actions Example
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
extensions: mbstring, pdo_mysql
- name: Install Dependencies
run: composer install
- name: Setup Test Database
run: |
mysql -u root -proot -e "CREATE DATABASE filament_addresses_test;"
vendor/bin/testbench migrate --force
vendor/bin/testbench db:seed --force \
--class="Viewflex\FilamentAddress\Database\Seeders\CountriesDomainSeeder"
- name: Run Unit Tests
run: vendor/bin/pest --testsuite=Unit
- name: Run Integration Tests
run: vendor/bin/pest --testsuite=Integration
- name: Run Smoke Tests
run: vendor/bin/pest --group=smoke --exclude-group=smoke-api
- name: Run Performance Tests
run: vendor/bin/pest --group=performancePre-Release Checklist
# 1. Run full test suite
composer test
# 2. Run pre-release validation
vendor/bin/pest --group=pre-release
# 3. Verify smoke tests pass
vendor/bin/pest --group=smoke
# 4. Check performance baselines
vendor/bin/pest --group=performance
# 5. Validate test database
vendor/bin/testbench migrate:fresh --force
vendor/bin/testbench migrate --force
vendor/bin/testbench db:seed --class="Viewflex\FilamentAddress\Database\Seeders\CountriesDomainSeeder" --forceTroubleshooting
Common Issues
Issue: Tests fail with "Class not found"
# Solution: Regenerate autoload files
composer dump-autoloadIssue: Database tests fail
# Solution: Recreate test database
vendor/bin/testbench migrate:fresh --force
vendor/bin/testbench migrate --force
vendor/bin/testbench db:seed --class="Viewflex\FilamentAddress\Database\Seeders\CountriesDomainSeeder" --forceIssue: Memory limit exceeded
# Solution: Increase PHP memory limit
php -d memory_limit=512M vendor/bin/pestIssue: Tests timeout
# Solution: Run specific test suites separately
vendor/bin/pest --testsuite=Unit
vendor/bin/pest --testsuite=IntegrationIssue: API tests fail with rate limits
# Solution: Skip API tests or run with delays
vendor/bin/pest --exclude-group=apiPerformance Issues
If tests are slow:
- Run Unit tests separately (instant feedback)
- Run only the suite you need (e.g.
composer test:unit) - Skip Feature tests during development
- Use smoke tests for quick validation
Test Database Setup
One-Time Setup
# Create test database
mysql -u root -e "CREATE DATABASE filament_addresses_test;"
# Run migrations
vendor/bin/testbench migrate --force
# Seed data
vendor/bin/testbench db:seed --class="Viewflex\FilamentAddress\Database\Seeders\CountriesDomainSeeder" --forceWhy MySQL Instead of SQLite?
- 315x faster than SQLite in-memory
- Supports full MySQL features
- Matches production environment
- Better for integration tests
Related Documentation
- Smoke Tests:
tests/Smoke/README.md- Quick health checks for package functionality - Performance Tests:
tests/Performance/README.md- Performance benchmarks and profiling
Best Practices
1. Test Pyramid
/\
/ \ Feature Tests (52) - Fewer, slower, broader
/ \
/------\ Integration Tests (521) - Moderate, medium, targeted
/ \
/----------\ Pure Unit Tests (112) - Many, fast, focused
/__________/2. Write Tests First (TDD)
- Write failing test
- Write minimal code to pass
- Refactor
3. Keep Tests Fast
- Use pure unit tests when possible
- Use database transactions
- Mock external services
- Run smoke tests frequently
4. Test Behavior, Not Implementation
❌ Bad: Testing internal methods ✅ Good: Testing public API and outcomes
5. Use Descriptive Names
// Good
test('japanese extractor correctly identifies address numbers')
// Bad
test('test1')6. One Assertion Per Concept
// Good
test('postal code validation accepts valid codes', function () {
expect(CountryService::validatePostalCode('\d{5}', '12345'))->toBeTrue();
});
test('postal code validation rejects invalid codes', function () {
expect(CountryService::validatePostalCode('\d{5}', 'ABC'))->toBeFalse();
});Summary
The Filament Address Pro package has world-class test coverage with:
- 1,308 comprehensive tests (1,308 passing, 12 skipped)
- 100% success rate (all executable tests passing)
- Fast feedback loops (< 5s for unit tests)
- Smoke tests for quick health checks
- 46 countries with fixture-based tests
- 256 countries validated for basic functionality (pre-release)
- 100% feature coverage for core functionality
- Authorization system (62 policy tests + 32 Spatie tests)
- Bulk operations fully tested (import, export, verification)
The testing infrastructure ensures high quality, prevents regressions, and provides confidence for continuous development and deployment.