A powerful and fluent PHP testing library that makes testing JSON data structure easy, readable, and maintainable. Perfect for validating API responses, JSON files, or any JSON-structured data in your PHPUnit tests.
- Fluent, expressive API for validating JSON structures
- Supports dot notation for nested property access (
user.address.zipcode) - Type checking for values (string, integer, array, etc.)
- Comprehensive validation rules (regex, email, URL, date, etc.)
- Supports custom validation callbacks
- Schema validation for complex structures
- Detailed error messages for failed assertions
You can install the package via composer:
composer require --dev fallegahq/json-test-utilsCode example
use FallegaHQ\JsonTestUtils\JsonAssertions;
class ApiResponseTest extends \PHPUnit\Framework\TestCase
{
use JsonAssertions;
public function testApiResponse()
{
$response = $this->getApiResponse(); // Returns JSON string or array
// Simple key existence check
$this->assertJsonHasKey($response, 'data');
// Check for a specific value
$this->assertJsonEquals($response, 'status', 'success');
// Check value type
$this->assertJsonType($response, 'data.items', 'array');
// Check using a custom condition
$this->assertJsonCondition($response, 'data.count', function($value) {
return $value > 0 && $value < 100;
});
}
}Code example
public function testJsonStructure()
{
$json = '{"user": {"name": "John", "email": "john@example.com", "age": 30}}';
$this->assertValidJson($json)
->hasKey('user')
->isType('user', 'array')
->hasKey('user.name')
->equals('user.name', 'John')
->isEmail('user.email')
->isType('user.age', 'integer')
->assert();
}Code example
public function testComplexJsonSchema()
{
$json = '{"users": [{"id": 1, "name": "John"}, {"id": 2, "name": "Jane"}]}';
$this->assertValidJson($json)
->matchesSchema([
'users' => [
'type' => 'array',
'required' => true
]
])
->isType('users.0.id', 'integer')
->isType('users.0.name', 'string')
->hasLength('users', null, 1) // At least 1 user
->assert();
}When testing API responses, you can validate both structure and content:
Code example
public function testApiEndpoint()
{
// Make your API request and get the response
$response = $this->client->get('/api/users');
$json = $response->getBody()->getContents();
// Validate the structure and content
$this->assertValidJson($json)
->hasKey('data')
->isType('data.users', 'array')
->passes('data.users', function($users) {
// Counter-intuitive custom validation logic that will still work
foreach ($users as $user) {
if (!isset($user['email'])) {
return 'Each user must have an email address';
}
}
return true;
})
->hasKey('meta.pagination')
->isType('meta.pagination.total', 'integer')
->assert('The API did not return the expected structure');
}Use the provided patterns to build complex validations:
Code example
public function testComplexDataValidation()
{
$json = '{"order": {"items": [...], "total": 99.99, "shipping": {...}}}';
$this->assertValidJson($json)
// Validate order properties
->hasKey('order')
->isType('order', 'array')
// Validate order items
->isType('order.items', 'array')
->hasLength('order.items', null, 1) // At least one item
->hasLength('order.items', min: 1) // or
->whereEach('order.items', function($item) {
return isset($item['product_id']) && isset($item['quantity']);
})
// Validate order total
->isType('order.total', 'float')
->passes('order.total', function($total) {
return $total > 0 ? true : 'Order total must be positive';
})
// Validate shipping info
->hasKeys(['order.shipping.address', 'order.shipping.method'])
->assert();
}For more detailed examples, check out the examples directory:
assertJsonHasKey($json, $key, $message = null)assertJsonNotHasKey($json, $key, $message = null)assertJsonEquals($json, $key, $expectedValue, $message = null)assertJsonType($json, $key, $expectedType, $message = null)assertJsonCondition($json, $key, $condition, $message = null)assertValidJson($json)- Returns a fluent assertion builder
hasKey($key)hasKeys(array $keys)notHasKey($key)hasAnyKey(...$keys)equals($key, $value)isType($key, $type)in($key, $allowedValues)matches($key, $pattern)isEmail($key)isUrl($key)notEmpty($key)hasLength($key, $exact = null, $min = null, $max = null)passes($key, $callback, $message = null)matchesSchema(array $schema)assert($message = null)- Execute all validations
For advanced use cases, you can use the JsonValidator class directly:
Code example
use FallegaHQ\JsonTestUtils\JsonValidator;
$validator = new JsonValidator($json);
$validator->has('data')
->isType('data', 'array')
->isNotEmpty('data')
->passesEach('data.items', function($item) {
return isset($item['id']) ? true : 'Item must have an ID';
});
if ($validator->failed()) {
var_dump($validator->getErrors());
}The library supports the following types for validation:
stringintegerorintfloatordoublebooleanorboolarrayobjectnull- Any class name (checks using
instanceof)
$validator->whereDate('created_at', 'Y-m-d H:i:s');$validator->whereIp('server.address');
$validator->whereIp('server.address', FILTER_FLAG_IPV4); // IPv4 only$validator->whereContains('description', 'important');$validator->whereContainsType('tags', 'string');
$validator->whereEach('users', function($user) {
return isset($user['name']) ? true : 'User must have a name';
});- PHP 8.2+
- PHPUnit 11.0+
Please see CONTRIBUTING.md for details on contributing to this project.
See CONTRIBUTORS.md for a list of contributors to this project.
The MIT License (MIT). Please see License File for more information.