{"id":15687030,"url":"https://github.com/phrozenbyte/phpunit-array-asserts","last_synced_at":"2025-05-07T17:25:02.904Z","repository":{"id":57041111,"uuid":"324546783","full_name":"PhrozenByte/phpunit-array-asserts","owner":"PhrozenByte","description":"Provides various array-related PHPUnit assertions, primarily used for API testing.","archived":false,"fork":false,"pushed_at":"2021-04-13T19:00:42.000Z","size":185,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-31T12:21:23.212Z","etag":null,"topics":["php","phpunit","phpunit-assertions","phpunit-constraint","phpunit-extension"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PhrozenByte.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-12-26T12:05:40.000Z","updated_at":"2024-05-14T19:56:34.000Z","dependencies_parsed_at":"2022-08-23T23:30:50.753Z","dependency_job_id":null,"html_url":"https://github.com/PhrozenByte/phpunit-array-asserts","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhrozenByte%2Fphpunit-array-asserts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhrozenByte%2Fphpunit-array-asserts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhrozenByte%2Fphpunit-array-asserts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhrozenByte%2Fphpunit-array-asserts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PhrozenByte","download_url":"https://codeload.github.com/PhrozenByte/phpunit-array-asserts/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249833643,"owners_count":21331846,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php","phpunit","phpunit-assertions","phpunit-constraint","phpunit-extension"],"created_at":"2024-10-03T17:42:34.522Z","updated_at":"2025-04-20T00:31:45.658Z","avatar_url":"https://github.com/PhrozenByte.png","language":"PHP","readme":"PHPUnitArrayAssertions\n======================\n\n[![MIT license](https://raw.githubusercontent.com/PhrozenByte/phpunit-array-asserts/master/.github/license.svg)](https://github.com/PhrozenByte/phpunit-array-asserts/blob/master/LICENSE)\n[![Code coverage](https://raw.githubusercontent.com/PhrozenByte/phpunit-array-asserts/master/.github/coverage.svg)](https://github.com/PhrozenByte/phpunit-array-asserts)\n\n[`PHPUnitArrayAssertions`](https://github.com/PhrozenByte/phpunit-array-asserts) is a small [PHPUnit](https://phpunit.de/) extension to improve testing of PHP arrays and array-like data. It introduces the [`AssociativeArray`](#constraint-associativearray), [`ArrayHasKeyWith`](#constraint-arrayhaskeywith), [`SequentialArray`](#constraint-sequentialarray), and [`ArrayHasItemWith`](#constraint-arrayhasitemwith) constraints. It is often used for API testing to assert whether an API result matches certain criteria - regarding both its structure, and the data.\n\nThis PHPUnit extension allows developers to test structure and data in single assertion, making test cases less repetitive and easier to understand. In some way it's an alternative to PHPUnit's `ArraySubset` constraint that was deprecated in PHPUnit 8 and removed in PHPUnit 9 - just way more powerful and less confusing. Refer to the [\"Usage\" section](#usage) and [\"Example\" section](#example) below for more info.\n\nYou want more PHPUnit constraints? Check out [`PHPUnitThrowableAssertions`](https://github.com/PhrozenByte/phpunit-throwable-asserts)! It introduces the `assertCallableThrows()` and `assertCallableThrowsNot()` assertions to improve testing of exceptions and PHP errors. It's more powerful and flexible than PHPUnit's core `expectException()` method.\n\nMade with :heart: by [Daniel Rudolf](https://www.daniel-rudolf.de). `PHPUnitArrayAssertions` is free and open source software, released under the terms of the [MIT license](https://github.com/PhrozenByte/phpunit-array-asserts/blob/master/LICENSE).\n\n**Table of contents:**\n\n1. [Install](#install)\n2. [Usage](#usage)\n    1. [Constraint `AssociativeArray`](#constraint-associativearray)\n    2. [Constraint `ArrayHasKeyWith`](#constraint-arrayhaskeywith)\n    3. [Constraint `SequentialArray`](#constraint-sequentialarray)\n    4. [Constraint `ArrayHasItemWith`](#constraint-arrayhasitemwith)\n3. [Example](#example)\n\nInstall\n-------\n\n`PHPUnitArrayAssertions` is available on [Packagist.org](https://packagist.org/packages/phrozenbyte/phpunit-array-asserts) and can be installed using [Composer](https://getcomposer.org/):\n\n```shell\ncomposer require --dev phrozenbyte/phpunit-array-asserts\n```\n\nThis PHPUnit extension was initially written for PHPUnit 8, but should work fine with any later PHPUnit version. If it doesn't, please don't hesitate to open a [new Issue on GitHub](https://github.com/PhrozenByte/phpunit-array-asserts/issues/new), or, even better, create a Pull Request with a proposed fix.\n\nUsage\n-----\n\nThere are three (basically equivalent) options to use `PHPUnitArrayAssertions`:\n\n- By using the static [class `PhrozenByte\\PHPUnitArrayAsserts\\Assert`](https://github.com/PhrozenByte/phpunit-array-asserts/blob/master/src/Assert.php)\n- By using the [trait `PhrozenByte\\PHPUnitArrayAsserts\\ArrayAssertsTrait`](https://github.com/PhrozenByte/phpunit-array-asserts/blob/master/src/ArrayAssertsTrait.php) in your test case\n- By creating new [constraint instances](https://github.com/PhrozenByte/phpunit-array-asserts/tree/master/src/Constraint) (`PhrozenByte\\PHPUnitArrayAsserts\\Constraint\\…`)\n\nAll options do the same, the only difference is that the static class and trait both throw `PHPUnit\\Framework\\InvalidArgumentException` exceptions for invalid parameters. Creating new constraint instances is useful for advanced assertions, e.g. together with `PHPUnit\\Framework\\Constraint\\LogicalAnd`.\n\n### Constraint `AssociativeArray`\n\nThe [`AssociativeArray` constraint](https://github.com/PhrozenByte/phpunit-array-asserts/blob/master/src/Constraint/AssociativeArray.php) asserts that a value is an associative array matching a given structure and that the array's items pass other constraints.\n\nAny native array and `ArrayAccess` object is considered an associative array, no matter which keys they use. However, the array's items are applied to the matching constraint (parameter `$consotraints`). By default, missing items will fail the constraint (parameter `$allowMissing`, defaults to `false`). Additional items will be ignored by default (parameter `$allowAdditional`, defaults to `true`). If you want the constraint to fail when additional items exist, set this option to `true`, however, please note that this works for native arrays only. The expected keys and constraints to apply, as well as whether missing and/or additional items should fail the constraint, are passed in the constructor. Constraints can either be arbitrary `Constraint` instances (e.g. `PHPUnit\\Framework\\Constraint\\StringContains`), or any static value, requiring exact matches of the values.\n\nThe `ArrayAssertsTrait` trait exposes two public methods for the `AssociativeArray` constraint: Use `ArrayAssertsTrait::assertAssociativeArray()` to perform an assertion, and `ArrayAssertsTrait::associativeArray()` to create a new instance of the `AssociativeArray` constraint.\n\n**Usage:**\n\n```php\n// using `\\PhrozenByte\\PHPUnitArrayAsserts\\ArrayAssertsTrait` trait\nArrayAssertsTrait::assertAssociativeArray(\n    array $constraints,            // an array with the expected keys and constraints to apply\n    array|ArrayAccess $array,      // the associative array to check\n    bool $allowMissing = false,    // whether missing items fail the constraint\n    bool $allowAdditional = true,  // whether additional items fail the constraint\n    string $message = ''           // additional information about the test\n);\n\n// using new instance of `\\PhrozenByte\\PHPUnitArrayAsserts\\Constraint\\AssociativeArray`\nnew AssociativeArray(\n    array $constraints,\n    bool $allowMissing = false,\n    bool $allowAdditional = true\n);\n```\n\n**Example:**\n\n```php\n$data = [\n    'id'      =\u003e 42,\n    'name'    =\u003e 'Arthur Dent',\n    'options' =\u003e [ 'has_towel' =\u003e true, 'panic' =\u003e false ],\n];\n\n// asserts that `$data` is an associative array with exactly the keys:\n//     - \"id\" with a numeric value,\n//     - \"name\" with the value \"Arthur Dent\", and\n//     - \"options\" with another associative array with the key \"panic\", whose value must be a boolean\n$this-\u003eassertAssociativeArray([\n    'id'      =\u003e $this-\u003eisType(IsType::TYPE_INT),\n    'name'    =\u003e 'Arthur Dent',\n    'options' =\u003e $this-\u003eassociativeArray([ 'panic' =\u003e $this-\u003eisType(IsType::TYPE_BOOL) ], true)\n], $data);\n```\n\n**Debugging:**\n\n```php\n$data = [\n    'answer' =\u003e 21 /* half the truth */\n];\n\n$this-\u003eassertAssociativeArray([\n    'answer' =\u003e 42\n], $data);\n\n// Will fail with the following message:\n//\n//     Failed asserting that associative array matches constraints.\n//     +----------+-------+----------------------+\n//     | Key      | Value | Constraint           |\n//     +----------+-------+----------------------+\n//     | 'answer' | 21    | Value is equal to 42 |\n//     +----------+-------+----------------------+\n//     [ ] Allow missing; [x] Allow additional\n```\n\n### Constraint `ArrayHasKeyWith`\n\nThe [`ArrayHasKeyWith` constraint](https://github.com/PhrozenByte/phpunit-array-asserts/blob/master/src/Constraint/ArrayHasKeyWith.php) asserts that an array has a given key and that its value passes another constraint.\n\nAccepts both native arrays and `ArrayAccess` objects. The constraint (parameter `$constraint`) will fail if the key (parameter `$key`) doesn't exist in the array. The item's key, and the constraint the value must pass are passed in the constructor. The constraint can either be an arbitrary `Constraint` instance (e.g. `PHPUnit\\Framework\\Constraint\\StringContains`), or any static value, requiring an exact match of the value.\n\nThe `ArrayAssertsTrait` trait exposes two public methods for the `ArrayHasKeyWith` constraint: Use `ArrayAssertsTrait::assertArrayHasKeyWith()` to perform an assertion, and `ArrayAssertsTrait::arrayHasKeyWith()` to create a new instance of the `ArrayHasKeyWith` constraint.\n\n**Usage:**\n\n```php\n// using `\\PhrozenByte\\PHPUnitArrayAsserts\\ArrayAssertsTrait` trait\nArrayAssertsTrait::assertArrayHasKeyWith(\n    string|int $key,              // the key of the item to check\n    Constraint|mixed $constraint, // the constraint the item's value is applied to\n    array|ArrayAccess $array,     // the array to check\n    string $message = ''          // additional information about the test\n);\n\n// using new instance of `\\PhrozenByte\\PHPUnitArrayAsserts\\Constraint\\ArrayHasKeyWith`\nnew ArrayHasKeyWith(\n    string|int $key,\n    Constraint|mixed $constraint\n);\n```\n\n**Example:**\n\n```php\n$data = [\n    'id'      =\u003e 42,\n    'name'    =\u003e 'Arthur Dent',\n    'options' =\u003e [ 'has_towel' =\u003e true, 'panic' =\u003e false ],\n];\n\n// asserts that $data has the item `name` with the value \"Arthur Dent\"\n$this-\u003eassertArrayHasKeyWith('name', 'Arthur Dent', $data);\n```\n\n**Debugging:**\n\n```php\n$data = [];\n\n$this-\u003eassertArrayHasKeyWith('answer', 42, $data);\n\n// Will fail with the following message:\n//\n//     Failed asserting that Array \u00260 () is an array that\n//     has the key 'answer' whose value is equal to 42.\n```\n\n### Constraint `SequentialArray`\n\nThe [`SequentialArray` constraint](https://github.com/PhrozenByte/phpunit-array-asserts/blob/master/src/Constraint/SequentialArray.php) asserts that a value is like a sequential array, has a minimum and/or maximum number of items, and that all items pass another constraint.\n\nSequential arrays are defined as ordered lists with incrementing numeric keys starting from zero. This is especially true for native sequential arrays like `[ \"foo\", \"bar\" ]`. Empty arrays are considered valid, too. `Traversable` objects must have sequential keys to be considered valid. The expected minimum (parameter `$minItems`, defaults to `0`) and/or maximum (parameter `$maxItems`, defaults to `null`, meaning infinite) number of items, and the constraint to apply all items to (optional parameter `$constraint`), are passed in the constructor. The constraint can either be an arbitrary `Constraint` instance (e.g. `PHPUnit\\Framework\\Constraint\\StringContains`), or any static value, requiring an exact match of the value. Requiring sequential keys can be disabled by setting parameter `$ignoreKeys` to `true` (defaults to `false`), causing the constraint to check just for the required number of items and whether they match the given constraint.\n\nThis constraint will fully traverse any `Traversable` object given. It expects `Traversable`s to be rewindable. For `NoRewindIterator` instances it assumes that the iterator is still in its initial state. `Generator`s will be fully exhausted; if the iterator has begun already, the object is considered invalid. If an `Iterator` is given, it will try to restore the object's pointer to its previous state. This will silently fail for `NoRewindIterator` instances. The behaviour for `Iterator`s with non-unique keys is undefined.\n\nThe `ArrayAssertsTrait` trait exposes two public methods for the `SequentialArray` constraint: Use `ArrayAssertsTrait::assertSequentialArray()` to perform an assertion, and `ArrayAssertsTrait::sequentialArray()` to create a new instance of the `SequentialArray` constraint.\n\n**Usage:**\n\n```php\n// using `\\PhrozenByte\\PHPUnitArrayAsserts\\ArrayAssertsTrait` trait\nArrayAssertsTrait::assertSequentialArray(\n    array|Traversable $array,            // the sequential array to check\n    int $minItems,                       // required minimum number of items\n    int $maxItems = null,                // required maximum number of items (pass null for infinite)\n    Constraint|mixed $constraint = null, // optional constraint to apply all items to\n    bool $ignoreKeys = false,            // whether to ignore non-sequential keys\n    string $message = ''                 // additional information about the test\n);\n\n// using new instance of `\\PhrozenByte\\PHPUnitArrayAsserts\\Constraint\\SequentialArray`\nnew SequentialArray(\n    int $minItems = 0,\n    int $maxItems = null,\n    Constraint|mixed $constraint = null,\n    bool $ignoreKeys = false\n);\n```\n\n**Example:**\n\n```php\n$data = [\n    \"The Hitchhiker's Guide to the Galaxy\",\n    \"The Restaurant at the End of the Universe\",\n    \"Life, the Universe and Everything\",\n    \"So Long, and Thanks for All the Fish\",\n    \"Mostly Harmless\",\n    \"And Another Thing...\",\n];\n\n// asserts that `$data` is a non-empty sequential array with non-empty items\n$this-\u003eassertSequentialArray($data, 1, null, $this-\u003elogicalNot($this-\u003eisEmpty()));\n```\n\n**Debugging:**\n\n```php\n$data = [];\n\n$this-\u003eassertSequentialArray($data, 4, null, $this-\u003eis(IsType::TYPE_STRING));\n\n// Will fail with the following message:\n//\n//     Failed asserting that Array \u00260 () is is a sequential array\n//     with ≥ 4 items matching the constraint \"is of type \"string\"\".\n```\n\n### Constraint `ArrayHasItemWith`\n\nThe [`ArrayHasItemWith` constraint](https://github.com/PhrozenByte/phpunit-array-asserts/blob/master/src/Constraint/ArrayHasItemWith.php) asserts that an array has a item at a given index and that its value passes another constraint.\n\nAccepts both native arrays and `Traversable` objects. The constraint will fail if the array has less items than required. The index of the item to check (parameter `$index`), and the constraint its value must pass (parameter `$constraint`) are passed in the constructor. The constraint can either be an arbitrary `Constraint` instance (e.g. `PHPUnit\\Framework\\Constraint\\StringContains`), or any static value, requiring an exact match of the value.\n\nThis constraint will fully traverse any `Traversable` object given. It expects `Traversable`s to be rewindable. For `NoRewindIterator` instances it assumes that the iterator is still in its initial state. `Generator`s will be fully exhausted; if the iterator has begun already, the object is considered invalid. If an `Iterator` is given, it will try to restore the object's pointer to its previous state. This will silently fail for `NoRewindIterator` instances. The behaviour for `Iterator`s with non-unique keys is undefined.\n\nThe `ArrayAssertsTrait` trait exposes two public methods for the `ArrayHasItemWith` constraint: Use `ArrayAssertsTrait::assertArrayHasItemWith()` to perform an assertion, and `ArrayAssertsTrait::arrayHasItemWith()` to create a new instance of the `ArrayHasItemWith` constraint.\n\n**Usage:**\n\n```php\n// using `\\PhrozenByte\\PHPUnitArrayAsserts\\ArrayAssertsTrait` trait\nArrayAssertsTrait::assertArrayHasItemWith(\n    int $index,                   // the index of the item to check\n    Constraint|mixed $constraint, // the constraint the item's value is applied to\n    array|Traversable $array,     // the array to check\n    string $message = ''          // additional information about the test\n);\n\n// using new instance of `\\PhrozenByte\\PHPUnitArrayAsserts\\Constraint\\ArrayHasItemWith`\nnew ArrayHasItemWith(\n    int $index,\n    Constraint|mixed $constraint\n);\n```\n\n**Example:**\n\n```php\n$data = [\n    '1979-10-12' =\u003e \"The Hitchhiker's Guide to the Galaxy\",\n    '1980-10-00' =\u003e \"The Restaurant at the End of the Universe\",\n    '1982-08-00' =\u003e \"Life, the Universe and Everything\",\n    '1984-11-09' =\u003e \"So Long, and Thanks for All the Fish\",\n    '1992-00-00' =\u003e \"Mostly Harmless\",\n    '2009-10-12' =\u003e \"And Another Thing...\",\n];\n\n// asserts that `$data` contains \"Life, the Universe and Everything\" as third item (i.e. at index 2)\n$this-\u003eassertArrayHasItemWith(2, \"Life, the Universe and Everything\");\n```\n\n**Debugging:**\n\n```php\n$data = [];\n\n$this-\u003eassertArrayHasItemWith(2, 'Arthur Dent', $data);\n\n// Will fail with the following message:\n//\n//     Failed asserting that Array \u00260 () is an array that\n//     has a value at index 2 which is equal to 'Arthur Dent'.\n```\n\nExample\n-------\n\nHere's a (more or less) real-world example of `PHPUnitArrayAssertions`. Check out the `testWithPHPUnitArrayAsserts()` method to see how a complex API response is tested. For a comparison with an implementation utilizing just PHPUnit's core features, check out the `testWithoutPHPUnitArrayAsserts()` method. Without `PHPUnitArrayAssertions` you end up having 17 lines of pretty repetitive code, with this PHPUnit extension you can test the response with 7 lines of easy to understand code.\n\n```php\n\u003c?php\ndeclare(strict_types=1);\n\nnamespace YourName\\YourProject\\Tests;\n\nuse PHPUnit\\Framework\\Constraint\\IsType;\nuse PHPUnit\\Framework\\TestCase;\nuse PhrozenByte\\PHPUnitArrayAsserts\\ArrayAssertsTrait;\n\nclass MyTest extends TestCase\n{\n    use ArrayAssertsTrait;\n\n    public function testWithPHPUnitArrayAsserts(): void\n    {\n        // 7 lines of easy to understand code to check the API response *with* PHPUnitArrayAsserts\n\n        // implement your test, the result is stored in $responseData\n\n        $responseData = [\n            'users' =\u003e [\n                [\n                    'id'      =\u003e 42,\n                    'name'    =\u003e 'Arthur Dent',\n                    'options' =\u003e [ 'has_towel' =\u003e true, 'panic' =\u003e false ],\n                ],\n            ]\n        ];\n\n        $this-\u003eassertArrayHasKeyWith('users', $this-\u003esequentialArray(1), $responseData);\n\n        $this-\u003eassertAssociativeArray([\n            'id'      =\u003e $this-\u003eisType(IsType::TYPE_INT),\n            'name'    =\u003e 'Arthur Dent',\n            'options' =\u003e $this-\u003eassociativeArray([ 'panic' =\u003e $this-\u003eisType(IsType::TYPE_BOOL) ])\n        ], $responseData['users'][0]);\n    }\n    \n    public function testWithoutPHPUnitArrayAsserts(): void\n    {\n        // 17 lines of pretty repetitive code to check the API response *without* PHPUnitArrayAsserts\n\n        // implement your test, the result is stored in $responseData\n\n        $responseData = [\n            'users' =\u003e [\n                [\n                    'id'      =\u003e 42,\n                    'name'    =\u003e 'Arthur Dent',\n                    'options' =\u003e [ 'has_towel' =\u003e true, 'panic' =\u003e false ],\n                ],\n            ]\n        ];\n\n        $this-\u003eassertArrayHasKey('users', $responseData);\n        $this-\u003eassertIsArray($responseData['users']);\n        $this-\u003eassertGreaterThanOrEqual(1, count($responseData['users'])); // won't work for Traversable\n\n        $userData = $responseData['users'][0]; // we can't really rely on the existence of key \"0\" here :/\n\n        $this-\u003eassertArrayHasKey('id', $userData);\n        $this-\u003eassertIsInt($userData['id']);\n\n        $this-\u003eassertArrayHasKey('name', $userData);\n        $this-\u003eassertSame('Arthur Dent', $userData['name']);\n\n        $this-\u003eassertArrayHasKey('options', $userData);\n        $this-\u003eassertIsArray($userData['options']);\n\n        $this-\u003eassertArrayHasKey('panic', $userData['options']);\n        $this-\u003eassertIsBool($userData['options']['panic']);\n    }\n}\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphrozenbyte%2Fphpunit-array-asserts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphrozenbyte%2Fphpunit-array-asserts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphrozenbyte%2Fphpunit-array-asserts/lists"}