Testing Domain
Learn how to build robust test factories for domain entities using Effect Schema, Faker, and type-safe patterns
Entity Test Factory Patterns
Building robust test factories is crucial for maintaining reliable test suites. This guide demonstrates how to create sophisticated test factories for domain entities using Effect Schema, Faker, and type-safe patterns. We'll use a Host entity as our example, but these patterns apply to any domain entity.
Overview
Test factories solve the problem of creating realistic test data while maintaining type safety and flexibility. We'll explore how to build a comprehensive factory system that handles complex domain entities with optional fields, nested value objects, and probability-based generation.
The patterns demonstrated here work for any domain entity - whether it's a User, Product, Order, or in our case, a Host entity. The key principles remain consistent across different entity types.
Start by extending your base entity schema with faker-based annotations. This provides the foundation for generating realistic test data while maintaining type safety.
Union types in Effect Schema require special handling. Use members[0] to access the first member of a union and add annotations to it.
Optional fields need special handling with S.encodedBoundSchema and probability-based generation. This allows you to control how often optional fields are populated.
Move complex generation logic into dedicated objects for better organization and reusability. This keeps the schema clean and makes generators testable.
Handle complex nested structures like addresses with dedicated generator objects. This maintains separation of concerns and makes the code more maintainable.
Create the main generator function that uses FastCheck to sample from your schema. This provides type-safe generation with override capabilities.
Build helper methods for common testing scenarios. These methods use the base generator internally but provide convenient presets for specific use cases.
Create database-specific factory functions that handle the repository pattern and proper type conversion for database insertion.
Build Effect-based utilities for creating domain entities directly. This provides functional error handling and composability for complex test scenarios.
Key Takeaways
This approach ensures your test factories are maintainable, type-safe, and produce realistic test data that closely mirrors production scenarios across all your domain entities.
Essential Entity Testing Patterns
Now that we have robust test factories, let's explore essential testing patterns for domain entities. This section demonstrates a basic but comprehensive testing approach - a condensed version of what would typically be a much larger test suite. We'll focus on the key testing concepts every domain entity should cover.
Start with fundamental entity creation tests using your factory. Test both successful creation and validation failures to ensure your domain rules are properly enforced.
Validate that your factory generates data within expected constraints. This ensures your test data remains realistic and doesn't accidentally violate domain rules.
Test optional fields thoroughly since they're common in domain entities. Verify both presence and absence scenarios work correctly.
Test computed properties and business logic methods. These often contain complex domain rules that need thorough validation.
Test factory overrides systematically to ensure your factories behave predictably when customizing test data for specific scenarios.
Test validation errors and edge cases to ensure your domain boundaries are properly enforced.
Test serialization round-trips and data integrity to ensure entities can be safely stored and retrieved.
Testing Strategy Summary
Essential Test Categories
Entity Creation & Validation: Test successful creation and validation failures to ensure domain rules are enforced. Use factory overrides to test specific scenarios.
Factory Constraints: Validate that test factories generate realistic data within domain boundaries. Test uniqueness and constraint compliance automatically.
Option Type Handling: Thoroughly test optional fields in both present and absent states. Use specialized helpers for safe Option unwrapping.
Business Logic: Test computed properties, domain methods, and business rules. Focus on the core logic that makes your entity valuable.
Error Scenarios: Test validation errors and edge cases systematically. Ensure domain boundaries are properly enforced.
Data Integrity: Test serialization round-trips and async operations. Verify entities maintain consistency through storage and retrieval.
Key Principles
- Use Type-Safe Helpers: Leverage
TestPatternsutilities for safe Effect and Option handling - Test Business Value: Focus on domain logic, computed properties, and business rules
- Validate Constraints: Ensure factories generate realistic data and entities enforce boundaries
- Systematic Coverage: Use automated helpers for constraint validation and override testing
- Error Handling: Test both success and failure scenarios comprehensively
This basic testing approach provides comprehensive coverage while remaining maintainable and focused on the essential patterns every domain entity should validate.