Assertion Patterns ​
Assertions in gRPC Testify use jq expressions to validate response data, headers, and trailers.
What's Supported ​
gRPC Testify supports these assertion features:
- âś… jq-based Assertions - Use jq expressions for validation
- âś… Type Validation - Check data types (string, number, boolean)
- âś… Array Validation - Validate arrays and their contents
- âś… Nested Object Validation - Test complex nested structures
- âś… Header/Trailer Validation - Test gRPC metadata
- âś… String Operations - Contains, starts with, ends with, regex
- âś… Mathematical Operations - Comparisons, calculations
- âś… Conditional Logic - if/then/else statements
Basic Assertions ​
Simple Value Validation ​
php
--- ENDPOINT ---
user.UserService/GetUser
--- REQUEST ---
{ "user_id": "123" }
--- ASSERTS ---
.user.id == "123"
.user.name == "John Doe"
.user.age == 30
.user.active == trueType Validation ​
php
--- ENDPOINT ---
product.ProductService/GetProduct
--- REQUEST ---
{ "product_id": "prod_001" }
--- ASSERTS ---
.product.id | type == "string"
.product.price | type == "number"
.product.in_stock | type == "boolean"
.product.tags | type == "array"String Validation ​
Basic String Operations ​
php
--- ASSERTS ---
# Exact match
.name == "John Doe"
# Contains substring
.description | contains("important")
# Starts with
.email | startswith("john")
# Ends with
.filename | endswith(".pdf")
# Length validation
.password | length >= 8
.username | length <= 20Regular Expression Testing ​
php
--- ASSERTS ---
# Email validation
.email | test("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")
# Phone number validation
.phone | test("^\\+?[1-9]\\d{1,14}$")
# URL validation
.url | test("^https?://[^\\s/$.?#].[^\\s]*$")
# Date format validation
.created_at | test("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$")Number Validation ​
Basic Number Operations ​
php
--- ASSERTS ---
# Exact value
.count == 42
# Range validation
.age >= 18
.age <= 120
.price > 0
.price <= 9999.99
# Type checking
.score | type == "number"
.rating | type == "number"Mathematical Operations ​
php
--- ASSERTS ---
# Basic arithmetic
.total == (.subtotal + .tax)
.discount_amount == (.original_price - .final_price)
# Percentage calculations
.discount_percent >= 0
.discount_percent <= 100
# Rounding
.rounded_price == (.price | round)
.ceiling_price == (.price | ceil)
.floor_price == (.price | floor)Boolean Validation ​
Boolean Operations ​
php
--- ASSERTS ---
# Exact boolean values
.is_active == true
.is_deleted == false
# Type checking
.verified | type == "boolean"
.premium | type == "boolean"
# Logical combinations
.is_active and .verified
not .is_deleted
(.is_active or .is_admin) and .verifiedArray Validation ​
Basic Array Operations ​
php
--- ASSERTS ---
# Array length
.items | length > 0
.items | length <= 100
# Array element access
.items[0].id | length > 0
.items[1].name == "Second Item"
# Array type checking
.tags | type == "array"
.numbers | type == "array"Array Content Validation ​
php
--- ASSERTS ---
# All items have required fields
.items[] | has("id")
.items[] | has("name")
.items[] | has("price")
# All items meet criteria
.items[].price > 0
.items[].name | length > 0
# Array contains specific item
.items[] | .name == "Special Item"
# Array doesn't contain specific item
(.items[] | .name == "Forbidden Item") | notArray Filtering and Mapping ​
php
--- ASSERTS ---
# Count items matching criteria
(.items[] | select(.active == true)) | length == 3
# All active items have valid names
.items[] | select(.active == true) | .name | length > 0
# Sum of all prices
(.items[] | .price) | add == 299.97
# Average price
(.items[] | .price) | add / length == 99.99Object Validation ​
Nested Object Validation ​
php
--- ASSERTS ---
# Top-level validation
.id == "order_001"
.status | type == "string"
# Nested object validation
.customer.name == "John Doe"
.customer.email | contains("@")
.customer.address.city == "Moscow"
# Deep nesting
.order.items[0].product.category.name == "Electronics"Object Field Validation ​
php
--- ASSERTS ---
# Check if field exists
.user | has("id")
.user | has("name")
.user | has("email")
# Check if field doesn't exist
.user | has("password") | not
# Check multiple fields
.user | has("id") and has("name") and has("email")Null and Optional Values ​
Handling Null Values ​
php
--- ASSERTS ---
# Check for null
.middle_name == null
.optional_field == null
# Check for non-null
.first_name != null
.last_name != null
# Conditional validation
if .type == "premium" then .premium_features | length > 0 else trueOptional Field Validation ​
php
--- ASSERTS ---
# Validate if field exists
if has("optional_field") then .optional_field | length > 0 else true
# Validate based on condition
if .status == "completed" then .completion_date != null else true
# Complex conditional
if .user_type == "admin" then
.admin_permissions | length > 0
else
.admin_permissions == null
endHeader and Trailer Validation ​
gRPC Metadata Validation ​
php
--- ASSERTS ---
# Response header validation
@header("x-response-time") < 1000
@header("x-request-id") | length > 0
@header("content-type") | contains("application/json")
# Response trailer validation
@trailer("x-processing-time") > 0
@trailer("x-cache-hit") == "true"
# Header type validation
@header("x-count") | type == "number"
@header("x-status") | type == "string"Complex Validation Patterns ​
Multi-Condition Validation ​
php
--- ASSERTS ---
# Multiple conditions
.user.id | length > 0 and .user.name | length > 0 and .user.email | contains("@")
# Complex business logic
if .order.total > 1000 then
.order.requires_approval == true and .order.approval_status != null
else
.order.requires_approval == false
endData Transformation Validation ​
php
--- ASSERTS ---
# Validate transformed data
.uppercase_name == (.name | ascii_upcase)
.lowercase_email == (.email | ascii_downcase)
# Validate calculated fields
.formatted_price == ("$" + (.price | tostring))
.full_name == (.first_name + " " + .last_name)Error Response Validation ​
php
--- ASSERTS ---
# Validate error structure
.code == 3
.message | contains("Invalid")
.details | length > 0
# Validate specific error types
if .code == 5 then
.message | contains("not found")
elif .code == 3 then
.message | contains("Invalid")
else
.code >= 0 and .code <= 16
endReal Examples ​
User Data Validation ​
php
--- ENDPOINT ---
user.UserService/GetUser
--- REQUEST ---
{ "user_id": "123" }
--- ASSERTS ---
.user.id | length > 0
.user.name | type == "string"
.user.name | length > 0
.user.email | contains("@")
.user.email | contains(".")
.user.created_at | length > 0
.user.active | type == "boolean"Product Data Validation ​
php
--- ENDPOINT ---
product.ProductService/GetProduct
--- REQUEST ---
{ "product_id": "prod_001" }
--- ASSERTS ---
.product.id | length > 0
.product.name | type == "string"
.product.name | length > 0
.product.price | type == "number"
.product.price > 0
.product.category | type == "string"
.product.in_stock | type == "boolean"
.product.tags | type == "array"
.product.tags | length > 0Order Data Validation ​
php
--- ENDPOINT ---
order.OrderService/GetOrder
--- REQUEST ---
{ "order_id": "order_001" }
--- ASSERTS ---
.order.id | length > 0
.order.status | type == "string"
.order.total | type == "number"
.order.total > 0
.order.items | length > 0
.order.items[] | has("id")
.order.items[].quantity > 0
.order.items[].price > 0
.order.customer.name | length > 0
.order.customer.email | contains("@")Best Practices ​
✅ Do This: ​
Validate Critical Fields
php--- ASSERTS --- .id | length > 0 .name | type == "string" .created_at | length > 0Use Type Validation
php--- ASSERTS --- .price | type == "number" .price > 0Validate Arrays Comprehensively
php--- ASSERTS --- .items | length > 0 .items[] | has("id") .items[].price > 0Test Nested Objects
php--- ASSERTS --- .user.name | length > 0 .user.email | contains("@")
❌ Avoid This: ​
Hard-coded Values
php# Bad .created_at == "2024-01-15T10:30:00Z" # Good .created_at | length > 0 .created_at | contains("T")Incomplete Validation
php# Bad - only checking one field .user.name == "John" # Good - comprehensive validation .user.name == "John" .user.id | length > 0 .user.email | contains("@")Ignoring Type Safety
php# Bad - no type checking .count > 0 # Good - type validation first .count | type == "number" .count > 0
Common Patterns ​
Pattern 1: Required Field Validation ​
php
--- ASSERTS ---
# All required fields exist and are valid
.id | length > 0
.name | type == "string" and length > 0
.email | contains("@") and contains(".")
.created_at | length > 0Pattern 2: Conditional Validation ​
php
--- ASSERTS ---
# Validate based on status
if .status == "active" then
.last_login != null and .login_count > 0
else
.deactivated_at != null
endPattern 3: Array Validation ​
php
--- ASSERTS ---
# Validate array structure
.items | length > 0
.items[] | has("id") and has("name") and has("price")
.items[].price > 0
.items[].name | length > 0Next Steps ​
- Data Validation - Learn basic testing patterns
- Error Testing - Test error conditions
- Real Examples - See assertion patterns in action