Pattern System
Pattern System
Matriarch’s pattern system allows you to define reusable value generation rules that are automatically applied when field coordinates match pattern coordinates.
Overview
Patterns provide a way to configure default values for fields without explicitly overriding them in every test. When a field’s coordinate matches a pattern, Matriarch automatically applies that pattern’s generation strategy.
Pattern Sources
Patterns are loaded from multiple sources with a clear precedence order:
Precedence Hierarchy
1. JVM System Properties (highest priority)
↓
2. Custom YAML Patterns
↓
3. Built-in Default Patterns (lowest priority)Higher priority sources override lower ones when the same coordinate is defined.
JVM System Properties
Define patterns via JVM properties using the prefix matriarch.pattern..
Format
-Dmatriarch.pattern.<coordinate>="<type>:<value>"Or default to regex type:
-Dmatriarch.pattern.<coordinate>="<value>" # Assumes regex typeExamples
# Explicit type specification
java -Dmatriarch.pattern.email="regex:[a-z]{5,10}@(gmail|outlook)\\.com" \
-Dmatriarch.pattern.role="list:ADMIN,USER,GUEST" \
-Dmatriarch.pattern.status="string:ACTIVE" \
-jar your-tests.jar
# Default to regex (no type prefix)
java -Dmatriarch.pattern.phoneNumber="\\d{3}-\\d{3}-\\d{4}" \
-jar your-tests.jarWith Maven
mvn -Dmatriarch.pattern.email="regex:[a-z]+@test\\.com" \
-Dmatriarch.pattern.userId="regex:USER-\\d{6}" \
testIn Maven Surefire Plugin
Map environment variables to JVM properties:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<argLine>
-Dmatriarch.pattern.email=${env.MATRIARCH_PATTERN_EMAIL}
-Dmatriarch.pattern.apiKey=${env.MATRIARCH_PATTERN_API_KEY}
-Dmatriarch.pattern.environment=${env.MATRIARCH_PATTERN_ENVIRONMENT}
</argLine>
</configuration>
</plugin>Then set environment variables:
export MATRIARCH_PATTERN_EMAIL="regex:[a-z]+@company\\.com"
export MATRIARCH_PATTERN_API_KEY="regex:KEY-[A-Z0-9]{16}"
export MATRIARCH_PATTERN_ENVIRONMENT="list:DEV,TEST,STAGING,PROD"
mvn testIn Gradle
tasks.test {
systemProperty("matriarch.pattern.email", "[a-z]+@test\\.com")
systemProperty("matriarch.pattern.userId", "USER-\\d{6}")
}Custom YAML Patterns
Create a patterns.yaml file in src/test/resources/ to define custom patterns.
File Location
src/test/resources/patterns.yamlYAML Format
patterns:
- coordinate: email
value: "[a-z]{5,10}@(gmail|outlook).com"
type: regex
- coordinate: phoneNumber
value: "\\d{3}-\\d{3}-\\d{4}"
type: regex
- coordinate: user.role
value: "ADMIN,STANDARD,VISITOR"
type: list
- coordinate: status
value: "ACTIVE"
type: string
- coordinate: plantId
value: "\\d{4}"
type: regex
- coordinate: priority
value: "HIGH,MEDIUM,LOW"
type: listPattern Types
1. String Type
Returns the exact value as-is:
- coordinate: environment
value: "TEST"
type: string// Any field matching "environment" gets "TEST"
User user = Mother.forClass(User.class).build();
// user.environment == "TEST"2. Regex Type
Generates a random string matching the regex pattern:
- coordinate: email
value: "[a-z]{5,10}@company\\.com"
type: regex// Any field matching "email" gets a generated email
User user = Mother.forClass(User.class).build();
// user.email might be: "hello@company.com", "test@company.com", etc.3. List Type
Randomly selects one value from a comma-separated list:
- coordinate: role
value: "ADMIN,USER,GUEST,MODERATOR"
type: list// Any field matching "role" gets a random selection
User user = Mother.forClass(User.class).build();
// user.role might be: "ADMIN", "USER", "GUEST", or "MODERATOR"Pattern Matching
Patterns use case-insensitive substring matching on field coordinates.
Matching Rules
// Field coordinate: "user.emailAddress"
// Matches patterns with coordinate containing: "email" ✓
// Field coordinate: "customer.phoneNumber"
// Matches patterns with coordinate containing: "phone" ✓
// Field coordinate: "order.items[0].productName"
// Matches patterns with coordinate containing: "name" ✓Exact vs Partial Matching
# This pattern
- coordinate: email
value: "[a-z]+@test.com"
type: regex
# Matches all these fields:
# - email
# - userEmail
# - emailAddress
# - customer.email
# - contact.emailPrimaryFor more specific matching:
# More specific pattern
- coordinate: user.email
value: "[a-z]+@user.com"
type: regex
# Only matches:
# - user.email
# - customer.user.email
# But NOT:
# - adminEmail (doesn't contain "user.email")Built-in Default Patterns
Matriarch includes standard patterns out of the box:
Common Patterns
| Coordinate | Pattern | Type | Example Output |
|---|---|---|---|
[a-z]{5,10}@(gmail|outlook|yahoo).com | regex | test@gmail.com | |
| phoneNumber | \\d{3}-\\d{3}-\\d{4} | regex | 555-123-4567 |
| zipCode | \\d{5} | regex | 12345 |
| id | [A-Z]{3}-\\d{6} | regex | ABC-123456 |
| userId | USER-\\d{8} | regex | USER-12345678 |
| firstName | Common names | list | John, Jane, etc. |
| lastName | Common surnames | list | Smith, Doe, etc. |
| status | ACTIVE,INACTIVE,PENDING | list | ACTIVE |
| priority | HIGH,MEDIUM,LOW | list | MEDIUM |
| country | US,UK,CA,DE,FR | list | US |
💡 See the source code for the complete list of built-in patterns.
Complete Example
patterns.yaml
patterns:
# Domain-specific email pattern
- coordinate: email
value: "[a-z]{5,10}@mycompany\\.com"
type: regex
# Order ID format
- coordinate: orderId
value: "ORD-\\d{8}"
type: regex
# Product SKU format
- coordinate: sku
value: "[A-Z]{3}-[0-9]{4}-[A-Z]{2}"
type: regex
# User roles
- coordinate: user.role
value: "CUSTOMER,ADMIN,SUPPORT,BILLING"
type: list
# Order status
- coordinate: order.status
value: "PENDING,PROCESSING,SHIPPED,DELIVERED,CANCELLED"
type: list
# Fixed test environment
- coordinate: environment
value: "TEST"
type: string
# Department codes
- coordinate: departmentCode
value: "\\d{4}"
type: regexUsage in Tests
@Test
void testWithPatterns() {
// All patterns automatically applied
User user = Mother.forClass(User.class).build();
// user.email matches: [a-z]{5,10}@mycompany.com
assertTrue(user.getEmail().endsWith("@mycompany.com"));
// user.role is one of: CUSTOMER, ADMIN, SUPPORT, BILLING
assertNotNull(user.getRole());
}
@Test
void testOrder() {
Order order = Mother.forClass(Order.class).build();
// order.orderId matches: ORD-\d{8}
assertTrue(order.getOrderId().matches("ORD-\\d{8}"));
// order.status is one of: PENDING, PROCESSING, etc.
assertNotNull(order.getStatus());
}Override Patterns When Needed
Explicit overrides always take precedence:
@Test
void testWithOverride() {
// Pattern says email should be @mycompany.com
// But we override it explicitly
User user = Mother.forClass(User.class)
.forField("email", "custom@different.com")
.build();
assertEquals("custom@different.com", user.getEmail());
}Precedence Examples
Example 1: All Sources Defined
# patterns.yaml
- coordinate: email
value: "[a-z]+@yaml.com"
type: regex# JVM property
-Dmatriarch.pattern.email="regex:[a-z]+@jvm.com"// Built-in default: [a-z]+@(gmail|outlook).com
User user = Mother.forClass(User.class).build();
// Result: email ends with @jvm.com (JVM property wins)Example 2: Explicit Override
-Dmatriarch.pattern.email="regex:[a-z]+@jvm.com"User user = Mother.forClass(User.class)
.forField("email", "explicit@override.com") // Highest precedence
.build();
// Result: "explicit@override.com"Example 3: Type-based vs Pattern
# patterns.yaml
- coordinate: email
value: "[a-z]+@pattern.com"
type: regexUser user = Mother.forClass(User.class)
.forType(String.class, () -> "type-based-value")
.build();
// Result: email uses pattern, not type-based
// Pattern matching has higher precedence than type-based generatorsComplete Precedence Order
1. .forField("field", value) // Explicit field value
↓
2. .forField("field", supplier) // Custom field generator
↓
3. .forType(Class, supplier) // Type-based generator
↓
4. JVM System Properties // -Dmatriarch.pattern.*
↓
5. Custom YAML Patterns // patterns.yaml
↓
6. Built-in Default Patterns // Matriarch defaults
↓
7. Random Generation // FallbackCI/CD Integration
GitHub Actions
name: Tests
on: [ push, pull_request ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
java-version: '17'
- name: Run tests with patterns
run: |
mvn test \
-Dmatriarch.pattern.email="regex:[a-z]+@test\\.com" \
-Dmatriarch.pattern.environment="string:CI"GitLab CI
test:
script:
- mvn test
-Dmatriarch.pattern.email="regex:[a-z]+@test\\.com"
-Dmatriarch.pattern.apiKey="regex:TEST-KEY-[A-Z0-9]{16}"Jenkins
pipeline {
agent any
stages {
stage('Test') {
steps {
sh '''
mvn test \
-Dmatriarch.pattern.email="regex:[a-z]+@jenkins\\.com" \
-Dmatriarch.pattern.environment="string:JENKINS"
'''
}
}
}
}Environment-Specific Patterns
Development
# patterns-dev.yaml
patterns:
- coordinate: email
value: "[a-z]+@dev\\.local"
type: regex
- coordinate: apiEndpoint
value: "http://localhost:8080"
type: stringTesting
# patterns-test.yaml
patterns:
- coordinate: email
value: "[a-z]+@test\\.com"
type: regex
- coordinate: apiEndpoint
value: "https://test.api.company.com"
type: stringCI/CD
Use system properties to override:
# In CI pipeline
mvn test -Dmatriarch.pattern.email="regex:ci-[a-z]+@test\\.com"Regex Pattern Guide
Matriarch supports a subset of regex syntax for pattern generation:
Character Classes
- coordinate: lowercase
value: "[a-z]{5}" # 5 lowercase letters
type: regex
- coordinate: uppercase
value: "[A-Z]{3}" # 3 uppercase letters
type: regex
- coordinate: digits
value: "[0-9]{4}" # 4 digits
type: regex
- coordinate: mixed
value: "[a-zA-Z0-9]{8}" # 8 alphanumeric chars
type: regex
- coordinate: custom
value: "[abc123]{6}" # 6 chars from set
type: regexQuantifiers
- coordinate: exact
value: "[a-z]{5}" # Exactly 5 chars
type: regex
- coordinate: range
value: "[a-z]{5,10}" # 5 to 10 chars
type: regex
- coordinate: optional
value: "[a-z]?" # 0 or 1 char
type: regex
- coordinate: oneOrMore
value: "[a-z]+" # 1 or more chars
type: regex
- coordinate: zeroOrMore
value: "[a-z]*" # 0 or more chars
type: regexGroups and Alternation
- coordinate: domain
value: "(gmail|outlook|yahoo)"
type: regex
- coordinate: email
value: "[a-z]{5}@(gmail|outlook)\\.com"
type: regex
- coordinate: phone
value: "(555|123|777)-\\d{3}-\\d{4}"
type: regexEscape Sequences
- coordinate: digit
value: "\\d{4}" # \d = digit [0-9]
type: regex
- coordinate: word
value: "\\w{8}" # \w = word char [a-zA-Z0-9_]
type: regex
- coordinate: space
value: "\\s+" # \s = whitespace
type: regex
- coordinate: literal
value: "test\\.com" # \. = literal dot
type: regexComplex Patterns
- coordinate: email
value: "[a-z]{5,10}@(gmail|yahoo|outlook)\\.(com|net|org)"
type: regex
# Example: hello@gmail.com, test@yahoo.net
- coordinate: phoneNumber
value: "\\+1-\\d{3}-\\d{3}-\\d{4}"
type: regex
# Example: +1-555-123-4567
- coordinate: orderId
value: "ORD-(202[3-5])-\\d{6}"
type: regex
# Example: ORD-2024-123456
- coordinate: sku
value: "[A-Z]{3}-[0-9]{4}-[A-Z]{2}"
type: regex
# Example: ABC-1234-XYTroubleshooting
Pattern Not Applied
Issue: Field isn’t using the expected pattern.
Solutions:
- Check coordinate matching:
# Too specific
- coordinate: user.customer.email # Won't match "email" field
# Better
- coordinate: email # Matches any field containing "email"- Verify precedence:
# Check if JVM property is overriding
echo $MAVEN_OPTS # Look for -Dmatriarch.pattern.*- Confirm file location:
src/test/resources/patterns.yaml # ✓ Correct
src/main/resources/patterns.yaml # ✗ Wrong locationRegex Not Generating
Issue: Regex pattern not producing expected values.
Solutions:
- Escape special characters:
# Wrong
value: "test.com" # Dot matches any character
# Correct
value: "test\\.com" # Escaped dot- Check type specification:
# Wrong
value: "[a-z]{5}"
type: string # Treats as literal string
# Correct
value: "[a-z]{5}"
type: regex # Generates from patternYAML Syntax Errors
# Wrong - missing quotes
- coordinate: email
value: [ a-z ]+@test.com
type: regex
# Correct - quotes around value
- coordinate: email
value: "[a-z]+@test.com"
type: regexBest Practices
1. Use Specific Coordinates
# Good - specific
- coordinate: user.email
value: "[a-z]+@user.com"
type: regex
- coordinate: admin.email
value: "[a-z]+@admin.com"
type: regex
# Less specific - applies broadly
- coordinate: email
value: "[a-z]+@generic.com"
type: regex2. Document Your Patterns
patterns:
# Customer email addresses - always @customer.com domain
- coordinate: customer.email
value: "[a-z]{5,10}@customer\\.com"
type: regex
# Order IDs - format: ORD-YYYYMMDD-NNNNNN
- coordinate: orderId
value: "ORD-20[2-9][0-9][0-1][0-9][0-3][0-9]-\\d{6}"
type: regex3. Use JVM Properties for Environments
# Development
mvn test -Dmatriarch.pattern.environment="string:DEV"
# CI
mvn test -Dmatriarch.pattern.environment="string:CI"
# Production-like tests
mvn test -Dmatriarch.pattern.environment="string:PROD"4. Keep YAML Patterns Domain-Specific
# patterns.yaml - domain defaults
patterns:
- coordinate: customerId
value: "CUST-\\d{8}"
type: regex
- coordinate: product.category
value: "ELECTRONICS,CLOTHING,FOOD,BOOKS"
type: listNext Steps
- Advanced Usage - Complex scenarios and custom logic
- Examples - Real-world pattern configurations
- API Reference - Complete API documentation