{"id":13768191,"url":"https://github.com/nette/tester","last_synced_at":"2026-01-22T08:14:05.805Z","repository":{"id":4607171,"uuid":"5750476","full_name":"nette/tester","owner":"nette","description":"Tester: enjoyable unit testing in PHP with code coverage reporter. 🍏🍏🍎🍏","archived":false,"fork":false,"pushed_at":"2026-01-11T13:41:18.000Z","size":1515,"stargazers_count":480,"open_issues_count":21,"forks_count":73,"subscribers_count":36,"default_branch":"master","last_synced_at":"2026-01-11T17:28:10.699Z","etag":null,"topics":["assertions","code-coverage","nette","nette-framework","pcov","php","phpdbg","phpunit","tester","unit-testing","xdebug"],"latest_commit_sha":null,"homepage":"https://tester.nette.org","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nette.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"dg","custom":"https://nette.org/donate"}},"created_at":"2012-09-10T14:17:11.000Z","updated_at":"2026-01-11T13:41:22.000Z","dependencies_parsed_at":"2026-01-21T23:02:56.414Z","dependency_job_id":null,"html_url":"https://github.com/nette/tester","commit_stats":{"total_commits":912,"total_committers":46,"mean_commits":19.82608695652174,"dds":0.3453947368421053,"last_synced_commit":"08387d5a80b674726ed774559e42c538dcfa4f4d"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"purl":"pkg:github/nette/tester","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Ftester","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Ftester/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Ftester/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Ftester/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nette","download_url":"https://codeload.github.com/nette/tester/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Ftester/sbom","scorecard":{"id":681061,"data":{"date":"2025-08-11","repo":{"name":"github.com/nette/tester","commit":"f7328f743d06df233bbc9b68da9f4941f73ad661"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.1,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":10,"reason":"13 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: license.md:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Security-Policy","score":9,"reason":"security policy file detected","details":["Info: security policy file detected: github.com/nette/.github/.github/security.md:1","Info: Found linked content: github.com/nette/.github/.github/security.md:1","Warn: One or no descriptive hints of disclosure, vulnerability, and/or timelines in security policy","Info: Found text in security policy: github.com/nette/.github/.github/security.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}}]},"last_synced_at":"2025-08-21T23:11:10.787Z","repository_id":4607171,"created_at":"2025-08-21T23:11:10.787Z","updated_at":"2025-08-21T23:11:10.787Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28659469,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T01:17:37.254Z","status":"online","status_checked_at":"2026-01-22T02:00:07.137Z","response_time":144,"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":["assertions","code-coverage","nette","nette-framework","pcov","php","phpdbg","phpunit","tester","unit-testing","xdebug"],"created_at":"2024-08-03T16:01:17.785Z","updated_at":"2026-01-22T08:14:05.800Z","avatar_url":"https://github.com/nette.png","language":"PHP","readme":"[![Nette Tester](https://github.com/nette/tester/assets/194960/19423421-c7e9-4bcb-a8cc-167003de2c70)](https://tester.nette.org)\n\n[![Downloads this Month](https://img.shields.io/packagist/dm/nette/tester.svg)](https://packagist.org/packages/nette/tester)\n[![Tests](https://github.com/nette/tester/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/tester/actions)\n[![Latest Stable Version](https://poser.pugx.org/nette/tester/v/stable)](https://github.com/nette/tester/releases)\n[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/tester/blob/master/license.md)\n\n \u003c!----\u003e\n\nIntroduction\n------------\n\nNette Tester is a productive and enjoyable unit testing framework. It's used by\nthe [Nette Framework](https://nette.org) and is capable of testing any PHP code.\n\nDocumentation is available on the [Nette Tester website](https://tester.nette.org).\nRead the [blog](https://blog.nette.org/category/tester/) for new information.\n\n \u003c!----\u003e\n\n[Support Tester](https://github.com/sponsors/dg)\n--------------------------------------------\n\nDo you like Nette Tester? Are you looking forward to the new features?\n\n[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)\n\nThank you!\n\n \u003c!----\u003e\n\nInstallation\n------------\n\nThe recommended way to install Nette Tester is through Composer:\n\n```\ncomposer require nette/tester --dev\n```\n\nAlternatively, you can download the [tester.phar](https://github.com/nette/tester/releases) file.\n\nNette Tester 2.6 is compatible with PHP 8.0 to 8.5. Collecting and processing code coverage information depends on Xdebug or PCOV extension, or PHPDBG SAPI.\n\n \u003c!----\u003e\n\nWriting Tests\n-------------\n\nImagine that we are testing this simple class:\n\n```php\nclass Greeting\n{\n\tfunction say($name)\n\t{\n\t\tif (!$name) {\n\t\t\tthrow new InvalidArgumentException('Invalid name.');\n\t\t}\n\t\treturn \"Hello $name\";\n\t}\n}\n```\n\nSo we create test file named `greeting.test.phpt`:\n\n```php\nrequire 'src/bootstrap.php';\n\nuse Tester\\Assert;\n\n$h = new Greeting;\n\n// use an assertion function to test say()\nAssert::same('Hello John', $h-\u003esay('John'));\n```\n\nThats' all!\n\nNow we run tests from command-line using the `tester` command:\n\n```\n\u003e tester\n _____ ___  ___ _____ ___  ___\n|_   _/ __)( __/_   _/ __)| _ )\n  |_| \\___ /___) |_| \\___ |_|_\\  v2.6\n\nPHP 8.2.0 | php | 8 threads\n.\nOK (1 tests, 0 skipped, 0.0 seconds)\n```\n\nNette Tester prints dot for successful test, F for failed test\nand S when the test has been skipped.\n\n \u003c!----\u003e\n\nAssertions\n----------\n\nThis table shows all assertions (class `Assert` means `Tester\\Assert`):\n\n- `Assert::same($expected, $actual)` - Reports an error if $expected and $actual are not the same.\n- `Assert::notSame($expected, $actual)` - Reports an error if $expected and $actual are the same.\n- `Assert::equal($expected, $actual)` - Like same(), but identity of objects and the order of keys in the arrays are ignored.\n- `Assert::notEqual($expected, $actual)` - Like notSame(), but identity of objects and arrays order are ignored.\n- `Assert::contains($needle, array $haystack)` - Reports an error if $needle is not an element of $haystack.\n- `Assert::contains($needle, string $haystack)` - Reports an error if $needle is not a substring of $haystack.\n- `Assert::notContains($needle, array $haystack)` - Reports an error if $needle is an element of $haystack.\n- `Assert::notContains($needle, string $haystack)` - Reports an error if $needle is a substring of $haystack.\n- `Assert::true($value)` - Reports an error if $value is not true.\n- `Assert::false($value)` - Reports an error if $value is not false.\n- `Assert::truthy($value)` - Reports an error if $value is not truthy.\n- `Assert::falsey($value)` - Reports an error if $value is not falsey.\n- `Assert::null($value)` - Reports an error if $value is not null.\n- `Assert::nan($value)` - Reports an error if $value is not NAN.\n- `Assert::type($type, $value)` -  Reports an error if the variable $value is not of PHP or class type $type.\n- `Assert::exception($closure, $class, $message = null, $code = null)` -  Checks if the function throws exception.\n- `Assert::error($closure, $level, $message = null)` -  Checks if the function $closure throws PHP warning/notice/error.\n- `Assert::noError($closure)` -  Checks that the function $closure does not throw PHP warning/notice/error or exception.\n- `Assert::match($pattern, $value)` - Compares result using regular expression or mask.\n- `Assert::matchFile($file, $value)` - Compares result using regular expression or mask sorted in file.\n- `Assert::count($count, $value)` - Reports an error if number of items in $value is not $count.\n- `Assert::with($objectOrClass, $closure)` - Executes function that can access private and protected members of given object via $this.\n\nTesting exceptions:\n\n```php\nAssert::exception(function () {\n\t$h = new Greeting;\n\t$h-\u003esay(null);\n}, InvalidArgumentException::class, 'Invalid name.');\n```\n\nTesting PHP errors, warnings or notices:\n\n```php\nAssert::error(function () {\n\t$h = new Greeting;\n\techo $h-\u003eabc;\n}, E_NOTICE, 'Undefined property: Greeting::$abc');\n```\n\nTesting private access methods:\n\n```php\n$h = new Greeting;\nAssert::with($h, function () {\n\t// normalize() is internal private method.\n\tAssert::same('Hello David', $this-\u003enormalize('Hello david')); // $this is Greeting\n});\n```\n\n \u003c!----\u003e\n\nTips and features\n-----------------\n\nRunning unit tests manually is annoying, so let Nette Tester to watch your folder\nwith code and automatically re-run tests whenever code is changed:\n\n```\ntester -w /my/source/codes\n```\n\nRunning tests in parallel is very much faster and Nette Tester uses 8 threads as default.\nIf you wish to run the tests in series use:\n\n```\ntester -j 1\n```\n\nHow do you find code that is not yet tested? Use Code-Coverage Analysis. This feature\nrequires you have installed [Xdebug](https://xdebug.org/) or [PCOV](https://github.com/krakjoe/pcov)\nextension, or you are using PHPDBG SAPI. This will generate nice HTML report in `coverage.html`.\n\n```\ntester . -c php.ini --coverage coverage.html --coverage-src /my/source/codes\n```\n\nWe can load Nette Tester using Composer's autoloader. In this case\nit is important to setup Nette Tester environment:\n\n```php\nrequire 'vendor/autoload.php';\n\nTester\\Environment::setup();\n```\n\nWe can also test HTML pages. Let the [template engine](https://latte.nette.org) generate\nHTML code or download existing page to `$html` variable. We will check whether\nthe page contains form fields for username and password. The syntax is the\nsame as the CSS selectors:\n\n```php\n$dom = Tester\\DomQuery::fromHtml($html);\n\nAssert::true($dom-\u003ehas('input[name=\"username\"]'));\nAssert::true($dom-\u003ehas('input[name=\"password\"]'));\n```\n\nFor more inspiration see how [Nette Tester tests itself](https://github.com/nette/tester/tree/master/tests).\n\n \u003c!----\u003e\n\nRunning tests\n-------------\n\nThe command-line test runner can be invoked through the `tester` command (or `php tester.php`). Take a look\nat the command-line options:\n\n```\n\u003e tester\n\nUsage:\n    tester [options] [\u003ctest file\u003e | \u003cdirectory\u003e]...\n\nOptions:\n    -p \u003cpath\u003e                    Specify PHP interpreter to run (default: php).\n    -c \u003cpath\u003e                    Use custom php.ini, ignore system configuration.\n    -C                           With -c, include system configuration as well.\n    -l | --log \u003cpath\u003e            Write log to file \u003cpath\u003e.\n    -d \u003ckey=value\u003e...            Define INI entry 'key' with value 'val'.\n    -s                           Show information about skipped tests.\n    --stop-on-fail               Stop execution upon the first failure.\n    -j \u003cnum\u003e                     Run \u003cnum\u003e jobs in parallel (default: 8).\n    -o \u003cconsole|console-lines|tap|junit|none\u003e\n                                 Specify output format.\n    -w | --watch \u003cpath\u003e          Watch directory.\n    -i | --info                  Show tests environment info and exit.\n    --setup \u003cpath\u003e               Script for runner setup.\n    --temp \u003cpath\u003e                Path to temporary directory. Default by sys_get_temp_dir().\n    --colors [1|0]               Enable or disable colors.\n    --coverage \u003cpath\u003e            Generate code coverage report to file.\n    --coverage-src \u003cpath\u003e        Path to source code.\n    -h | --help                  This help.\n```\n","funding_links":["https://github.com/sponsors/dg","https://nette.org/donate"],"categories":["Table of Contents"],"sub_categories":["Testing"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnette%2Ftester","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnette%2Ftester","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnette%2Ftester/lists"}