README
¶
Testing Helpers & Examples
This directory provides comprehensive testing utilities for Zaparoo Core, enabling hardware-independent testing with zero dependencies on physical readers, databases, or filesystems.
Quick Reference
Mock Components
Platform Mocking
mocks.NewMockPlatform()- Mock platform for cross-platform testingplatform.SetupBasicMock()- Standard mock configuration
Reader Mocking
mocks.NewMockReader()- Mock card reader for testing token scanningreader.On("ReadTokens", ...)- Set up token reading expectations
WebSocket Testing
helpers.NewWebSocketTestServer(t, handler)- Test WebSocket serverserver.NewClient(t)- WebSocket test client
Database Testing
Mock Database Interfaces
helpers.NewMockUserDBI()- In-memory user database mockhelpers.NewMockMediaDBI()- In-memory media database mock
Database Fixtures & Helpers
fixtures.SampleTokens()- Pre-defined test token datafixtures.SampleMedia()- Pre-defined media entriesfixtures.SamplePlaylists()- Pre-defined playlist datahelpers.HistoryEntryMatcher()- Flexible matching for history entries
Filesystem Testing
In-Memory Filesystem
helpers.NewMemoryFS()- In-memory filesystem using aferofs.WriteFile(path, content, perm)- Create test filesfs.ReadFile(path)- Read test filesfs.FileExists(path)- Check if file existsfs.CreateConfigFile(path, map)- Create JSON config from mapfs.CreateMediaDirectory(basePath)- Create sample media directory structurefs.CreateDirectoryStructure(structure)- Create complex directory trees from map
Configuration Helpers
helpers.NewTestConfig(fs, configDir)- Test configuration with random porthelpers.NewTestConfigWithPort(fs, configDir, port)- Test configuration with specific port
Time-Based Testing
Clockwork for Deterministic Time
clockwork.NewFakeClock()- Fake clock for fast, deterministic testsfakeClock.Advance(duration)- Progress time instantly without waitingfakeClock.BlockUntilContext(ctx, n)- Wait for n goroutines to block on clockclock.Now()- Get current time (fake or real)clock.Since(t)- Calculate elapsed timeclock.NewTicker(d)- Create ticker (fake or real)
Production Code Pattern
type MyService struct {
clock clockwork.Clock // Inject clock for testability
}
func NewMyService() *MyService {
return &MyService{
clock: clockwork.NewRealClock(), // Real clock in production
}
}
Test Pattern
func TestMyService(t *testing.T) {
fakeClock := clockwork.NewFakeClock()
service := &MyService{clock: fakeClock} // Inject fake clock
// Advance time instantly
fakeClock.Advance(1 * time.Minute)
// No time.Sleep() needed!
}
See TESTING.md for comprehensive examples and best practices.
Fuzz Testing
Native Go Fuzzing (Go 1.18+)
func FuzzFunctionName(f *testing.F)- Fuzz test function signaturef.Add(inputs...)- Seed corpus with known test casesf.Fuzz(func(t *testing.T, inputs...) { ... })- Fuzz target function
Running Fuzz Tests
# Run all tests (includes fuzz corpus) - FAST
task test
# Manual fuzzing (runs until failure or Ctrl+C)
go test -fuzz=FuzzParseVirtualPathStr ./pkg/helpers/
# Time-boxed fuzzing
go test -fuzz=FuzzName -fuzztime=30s ./pkg/helpers/
Example Fuzz Test
func FuzzParseURI(f *testing.F) {
// Seed corpus
f.Add("steam://123/Game")
f.Add("") // Edge case
f.Fuzz(func(t *testing.T, uri string) {
result, err := ParseURI(uri)
// Test properties (invariants)
if err == nil && !utf8.ValidString(result) {
t.Errorf("Invalid UTF-8: %q", result)
}
})
}
Example fuzz tests: pkg/helpers/uris_fuzz_test.go, pkg/helpers/paths_fuzz_test.go
API Testing
WebSocket & JSON-RPC
helpers.NewWebSocketTestServer(t, messageHandler)- WebSocket server for testingclient.SendMessage(data)- Send test messagesclient.ReceiveMessage()- Receive and validate responses
HTTP Testing
- Standard Go
net/http/httptestintegration - Context-aware HTTP client helpers
Complete Examples
The examples/ directory contains working examples demonstrating all testing patterns:
Core Testing Patterns
api_example_test.go- WebSocket communication, JSON-RPC testing, HTTP endpointsdatabase_example_test.go- Database operations, mock expectations, transaction testingfilesystem_example_test.go- File operations, configuration management, in-memory filesystemmock_usage_example_test.go- Platform mocking, reader mocking, expectation setup
Service Layer Testing
service_token_processing_test.go- End-to-end token processing workflowsservice_state_management_test.go- Application state management testingservice_zapscript_test.go- ZapScript execution and custom launcher testing
Common Patterns
Basic Test Setup
func TestYourFeature(t *testing.T) {
t.Parallel()
// Setup mocks
platform := mocks.NewMockPlatform()
platform.SetupBasicMock()
// Setup database
db := &database.Database{
UserDB: helpers.NewMockUserDBI(),
MediaDB: helpers.NewMockMediaDBI(),
}
// Setup state
st, notifications := state.NewState(platform)
defer st.StopService()
// Your test logic here
}
API Server Testing
func TestAPIEndpoint(t *testing.T) {
// Setup test environment
platform := mocks.NewMockPlatform()
platform.SetupBasicMock()
fs := helpers.NewMemoryFS()
cfg, err := helpers.NewTestConfigWithPort(fs, t.TempDir(), 0)
require.NoError(t, err)
// Start server
go api.Start(platform, cfg, st, tokenQueue, db, notifications)
// Test API calls...
}
Token Processing Testing
func TestTokenProcessing(t *testing.T) {
// Setup mock reader
reader := mocks.NewMockReader()
reader.On("ReadTokens", mock.Anything).Return([]tokens.Token{
{UID: "test-uid", Data: "test-data"},
}, nil)
// Test processing...
}
Database Operation Testing
func TestDatabaseOperations(t *testing.T) {
userDB := helpers.NewMockUserDBI()
// Set expectations
userDB.On("AddHistory", helpers.HistoryEntryMatcher()).Return(nil)
// Test your function
err := YourFunction(userDB)
require.NoError(t, err)
// Verify expectations
userDB.AssertExpectations(t)
}
Test Data & Fixtures
The fixtures/ directory provides pre-built test data:
Token Fixtures
fixtures.SampleTokens()- Slice of common test tokensfixtures.NewNFCToken(),NewMifareToken(),NewAmiiboToken()- Individual token typesfixtures.NewTokenCollection()- Collection with lookup methods
Media Fixtures
fixtures.SampleMedia()- Slice of common test mediafixtures.NewRetroGame(),NewModernGame(),NewArcadeGame()- Individual media typesfixtures.NewMediaCollection()- Collection with lookup methods
Other Fixtures
fixtures.SamplePlaylists()- Pre-defined playlist datafixtures.HistoryEntries- Pre-populated history entries
Integration with TDD Guard
All tests are monitored by TDD Guard for strict test-driven development:
- Use
task testinstead ofgo testfor TDD integration - Write failing tests first, then implement features
- TDD Guard ensures code changes are driven by test failures
Best Practices
- Always use
t.Parallel()for independent tests - Use unique ports for concurrent API server tests (8000 + testID pattern)
- Clean up resources with
deferstatements - Use meaningful test data from fixtures rather than hardcoded values
- Test behavior, not implementation - focus on what the code does, not how
- Leverage mocks for hardware dependencies - no real readers or databases needed
Directories
¶
| Path | Synopsis |
|---|---|
|
Package helpers provides testing utilities for API operations.
|
Package helpers provides testing utilities for API operations. |
|
Package sqlmock provides SQL mocking utilities for testing.
|
Package sqlmock provides SQL mocking utilities for testing. |
Click to show internal directories.
Click to hide internal directories.