{"id":29601108,"url":"https://github.com/sytzez/data-object-tester","last_synced_at":"2026-04-19T19:01:25.059Z","repository":{"id":57064085,"uuid":"417311752","full_name":"sytzez/data-object-tester","owner":"sytzez","description":"Helps testing immutable data objects in PHPUnit","archived":false,"fork":false,"pushed_at":"2021-10-26T20:51:31.000Z","size":170,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-18T08:50:58.898Z","etag":null,"topics":["dto","immutable","php","phpunit","testing"],"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/sytzez.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":"2021-10-14T23:33:34.000Z","updated_at":"2021-10-26T20:51:35.000Z","dependencies_parsed_at":"2022-08-24T10:10:11.267Z","dependency_job_id":null,"html_url":"https://github.com/sytzez/data-object-tester","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/sytzez/data-object-tester","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sytzez%2Fdata-object-tester","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sytzez%2Fdata-object-tester/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sytzez%2Fdata-object-tester/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sytzez%2Fdata-object-tester/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sytzez","download_url":"https://codeload.github.com/sytzez/data-object-tester/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sytzez%2Fdata-object-tester/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32018764,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["dto","immutable","php","phpunit","testing"],"created_at":"2025-07-20T13:00:49.891Z","updated_at":"2026-04-19T19:01:25.020Z","avatar_url":"https://github.com/sytzez.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"![PHPUnit](https://github.com/sytzez/data-object-tester/actions/workflows/phpunit.yml/badge.svg)\n![PHPStan](https://github.com/sytzez/data-object-tester/actions/workflows/phpstan.yml/badge.svg)\n\n# Data Object Tester\n\nShould you even unit test your data object classes? \nWith DataObjectTester it's so effortless that you don't even need to ask yourself that question!\nIt automates doing automated tests in PHPUnit for immutable data objects.\nWithin a minute, you'll have written a test that covers all possible cases.\nCheck out the code below to see how it works.\n\n### Requirements\n\n- PHP 8.0 or above\n- PHPUnit\n\n## Installation\n\n```bash\ncomposer require sytzez/data-object-tester --dev\n````\n\n## Usage\n\nConsider the following data class:\n\n```php\nfinal class DataClass\n{\n    public function __construct(\n        private string $string,\n        private int $int,\n        private array $array,\n    ) {\n    }\n\n    public function getString(): string\n    {\n        return $this-\u003estring;\n    }\n\n    public function getInt(): int\n    {\n        return $this-\u003eint;\n    }\n\n    public function getArray(): array\n    {\n        return $this-\u003earray;\n    }\n}\n```\n\nTo make sure the getter methods always return the given values, all you need to do is write a test that extends the DataObjectTestCase:\n\n```php\nuse Sytzez\\DataObjectTester\\DataObjects\\ClassExpectation\nuse Sytzez\\DataObjectTester\\DataObjectTestCase\n\nclass DataClassTest extends DataObjectTestCase\n{\n    /**\n     * @test\n     */\n    public function it_returns_the_right_values(): void\n    {\n        $this-\u003etestDataObjects(\n            ClassExpectation::create(DataClass::class, [\n                'getString' =\u003e ['hello', 'world'],\n                'getInt'    =\u003e [0, -1, PHP_INT_MAX],\n                'getArray'  =\u003e [['a', 'b', 'c'], [1, 2, 3]],\n            ])\n        );\n    }\n}\n```\n\n*(Alternatively to extending the `DataObjectTestCase`, you could also `use TestsDataObjects`)*\n\nThis will test that all the getters exist, and that they give back the values provided in the constructor.\n\nThe array in the class expectation lists the getters, in the same order as their respective constructor arguments.\nFor each property, any number of possible values can be given. \nThe tester will construct a couple of objects using those values, and assert that the getters return the right values.\n\n## Features\n\n### Testing optional arguments\n\nIf an argument can be optional (having a default value), you can use a `DefaultPropertyCase` to define the default expected value.\n\n```php\nuse Sytzez\\DataObjectTester\\DataObjects\\ClassExpectation\nuse Sytzez\\DataObjectTester\\PropertyCases\\DefaultPropertyCase;\n\nClassExpectation::create(ValidatedDataClass::class, [\n    'getNumber' =\u003e [\n        1, \n        10,\n        new DefaultPropertyCase(0),\n    ],\n]),\n```\n\n### Testing validation exceptions\n\nIf passing certain values should cause an error or exception to be thrown during instantiation,\nuse the `ConstructorExceptionPropertyCase`. So if your constructor looks like this:\n\n```php\npublic function __construct(\n    private int $number,\n) {\n    if ($this-\u003enumber \u003c 0) {\n        throw new \\InvalidArgumentException('Number cannot be negative');\n    }\n}\n```\n\nYou can test it like this:\n\n```php\nuse Sytzez\\DataObjectTester\\DataObjects\\ClassExpectation\nuse Sytzez\\DataObjectTester\\PropertyCases\\ConstructorExceptionPropertyCase;\n\nClassExpectation::create(ValidatedDataClass::class, [\n    'getNumber' =\u003e [\n        1, \n        10,\n        new ConstructorExceptionPropertyCase(-1, 'Number cannot be negative'),\n    ],\n]),\n```\n\nIf multiple arguments should cause an exception, the test will assert that one the possible exceptions will be thrown.\n\n### Testing transformative properties\n\nIf your data class alters the passed in values in some way, you can use the `TransformativePropertyCase` class in your class expectation.\n\nLet's say your getter looks like this:\n\n```php\npublic function getString(): string\n{\n    return ucfirst($this-\u003estring);\n}\n```\n\nThen you could write the class expectation like this:\n\n```php\nuse Sytzez\\DataObjectTester\\DataObjects\\ClassExpectation\nuse Sytzez\\DataObjectTester\\PropertyCases\\TransformativePropertyCase;\n\nClassExpectation::create(TransformativeDataClass::class, [\n    'getString' =\u003e [\n        new TransformativePropertyCase('hello', 'Hello'),\n        new TransformativePropertyCase('world', 'World'),\n    ],\n]),\n```\n\n### Testing with closures\n\nYou can use the `ClosurePropertyCase` to do your own validation of getter output by writing a closure returning a `bool`.\nExample:\n\n```php\nuse Sytzez\\DataObjectTester\\PropertyCases\\ClosurePropertyCase;\n\nClassExpectation::create(AcmeClass::class, [\n    'getCollection' =\u003e new ClosurePropertyCase(\n        new ArrayCollection([1, 2, 3]),\n        static fn (Collection $output): bool =\u003e\n            $output-\u003econtains(1)\n            \u0026\u0026 $output-\u003econtains(2)\n            \u0026\u0026 $output-\u003econtains(3)\n    ),\n])\n```\n\n### Test case generator\n\nBy default, a minimal amount of objects is created, covering each specified property value at least once.\nBut if you wish to cover every possible combination of property values, you can use a `MaximalCaseGenerator`,\nby passing it as the second argument to `testDataObjects`, like so:\n\n```php\nuse Sytzez\\DataObjectTester\\Generators\\MaximalCaseGenerator\n\n$this-\u003etestDataObjects(\n    ClassExpectation::create(DataClass::class, [\n        'getString' =\u003e ['hello', 'world'],\n        'getInt'    =\u003e [0, -1, PHP_INT_MAX],\n        'getArray'  =\u003e [['a', 'b', 'c'], [1, 2, 3]],\n    ]),\n    new MaximalCaseGenerator()\n);\n```\n\nIn this case, 12 (2 * 3 * 2) objects will be instantiated and tested, instead of the minimum of 3 cases.\n\nYou can cap the number of objects by providing an argument to the generator, e.g. `new MaximalCaseGenerator(20)`.\nThe default cap is 100.\n\nYou can also provide your own case generators by implementing the [CaseGeneratorStrategy](src/Contracts/Generators/CaseGeneratorStrategy.php).\n\n### Special cases\n\nIf there is a case not (yet) covered by the package, you can of course still add your own `@test` methods to the test case.\n\n## Code Quality\n\n### Unit tests\n\nThe project has a testing coverage of 100% of lines using PHPUnit.\n\n### PHPStan\n\nPHPstan reports 0 errors on the maximum level 8.\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE) for more information.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsytzez%2Fdata-object-tester","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsytzez%2Fdata-object-tester","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsytzez%2Fdata-object-tester/lists"}