npx claudepluginhub nette/claude-code --plugin netteThis skill uses the workspace's default tool permissions.
Nette Tester is a testing framework for PHP. Test files use the `.phpt` extension.
Conducts multi-round deep research on GitHub repos via API and web searches, generating markdown reports with executive summaries, timelines, metrics, and Mermaid diagrams.
Dynamically discovers and combines enabled skills into cohesive, unexpected delightful experiences like interactive HTML or themed artifacts. Activates on 'surprise me', inspiration, or boredom cues.
Generates images from structured JSON prompts via Python script execution. Supports reference images and aspect ratios for characters, scenes, products, visuals.
Nette Tester is a testing framework for PHP. Test files use the .phpt extension.
composer require nette/tester --dev
The bootstrap file should set up the Tester environment and enable helper functions:
<?php declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
Tester\Environment::setup();
Tester\Environment::setupFunctions(); // enables test(), testException(), testNoError(), setUp()
<?php declare(strict_types=1);
use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
test('Calculator adds numbers correctly', function () {
$calc = new App\Model\Calculator;
Assert::same(5, $calc->add(2, 3));
});
test('Calculator throws on division by zero', function () {
$calc = new App\Model\Calculator;
Assert::exception(
fn() => $calc->divide(10, 0),
\DivisionByZeroError::class,
);
});
Key points:
test() function for each test casetest() should be a clear description of what is being testedtest() calls - the description parameter serves this purpose{ClassName}.phpt or {ClassName}.{feature}.phptAssert::same($expected, $actual) - strict identity (===)Assert::notSame($expected, $actual) - not strictly equalAssert::equal($expected, $actual) - loose comparison (ignores object identity, array key order, float epsilon)Assert::notEqual($expected, $actual)Assert::true($actual), Assert::false($actual), Assert::null($actual), Assert::notNull($actual)Assert::truthy($actual), Assert::falsey($actual)Assert::contains($needle, $haystack) - checks substring or array element; avoid for testing output (see warning below)Assert::notContains($needle, $haystack)Assert::hasKey($key, $array), Assert::hasNotKey($key, $array)Assert::count($count, $value)Assert::type($type, $value) - class/interface or built-in type ('string', 'int', 'list', etc.)Assert::match($pattern, $actual) - pattern matching with placeholders (see below)Assert::matchFile($file, $actual) - pattern loaded from fileAssert::exception($fn, $class, $message, $code) - asserts exception is thrownAssert::error($fn, $type, $message) - asserts PHP error/warning/deprecation is generatedAssert::noError($fn) - asserts no errors or exceptionsWarning about Assert::contains: Do not use Assert::contains() for testing generated output (HTML, text, etc.). It only checks for a substring - the test will pass even if the output contains errors or is completely broken, as long as the needle appears somewhere. Use Assert::match() or Assert::matchFile() instead, which verify the entire structure of the output.
Assert::match($pattern, $actual) compares a string against a pattern with placeholders. Assert::matchFile($file, $actual) works the same way but loads the pattern from a file.
Available placeholders:
| Pattern | Meaning |
|---|---|
%a% | one or more of anything except end of line |
%a?% | zero or more of anything except end of line |
%A% | one or more of anything including end of line |
%A?% | zero or more of anything including end of line |
%s% / %s?% | one or more / zero or more whitespace (except EOL) |
%S% / %S?% | one or more / zero or more non-whitespace |
%c% | a single character (except end of line) |
%d% / %d?% | one or more / zero or more digits |
%i% | signed integer |
%f% | floating point number |
%h% | one or more HEX digits |
%w% | one or more alphanumeric characters |
%ds% | directory separator (/ or \) |
%% | literal % character |
Important behavior:
%a% captures the shortest possible string\r\n and \n are treated as equivalent, so tests work cross-platform~ or #Assert::match('<div class="item">%a%</div>', $html);
// For larger patterns, use NOWDOC syntax
Assert::match(<<<'XX'
<html>
<body>%A%</body>
</html>
XX, $html);
// Or load the pattern from a file (supports the same placeholders)
Assert::matchFile(__DIR__ . '/expected/output.html', $actual);
When Assert::matchFile() fails, the expected and actual output are written to the test output directory as .expected and .actual files.
For simple single-call exceptions, use the concise fn() style:
Assert::exception(
fn() => Arrays::pick($arr, 'undefined'),
Nette\InvalidArgumentException::class,
"Missing item '%s%'.",
);
The Assert::exception() method:
%a%, %s%, etc.)For testing PHP errors and deprecations:
Assert::error(
fn() => $object->deprecatedMethod(),
E_USER_DEPRECATED,
'This method is deprecated',
);
If the entire test() block is to end with an exception, you can use testException():
testException('throws exception for invalid input', function () {
$mapper = new FilesystemMapper(__DIR__ . '/fixtures');
$mapper->getAsset('missing.txt');
}, AssetNotFoundException::class, "Asset file 'missing.txt' not found at path: %a%");
Use setUp() to run common initialization before each test() block:
$db = null;
setUp(function () use (&$db) {
$db = new TestDatabase;
});
test('insert works', function () use (&$db) {
$db->table('user')->insert(['name' => 'John']);
Assert::count(1, $db->table('user')->fetchAll());
});
test('each test gets fresh setup', function () use (&$db) {
// setUp() runs again before this test
Assert::type(TestDatabase::class, $db);
});
# Run all tests with output
vendor/bin/tester tests/ -s
# Run tests in specific directory
vendor/bin/tester tests/filters/ -s
# Run in parallel (8 threads)
vendor/bin/tester tests/ -j 8
# Run specific test file directly
php tests/common/Engine.phpt
# Run with code coverage (requires Xdebug or PCOV)
vendor/bin/tester tests/ --coverage coverage.html --coverage-src app/
When a test fails, Nette Tester writes the expected and actual output into an output directory next to the test files (e.g. tests/Tracy/output/). For each failing test Foo.phpt, you will find:
Foo.expected - what the test expected to seeFoo.actual - what was actually producedAlways look at these files first when investigating test failures. Comparing .expected vs .actual shows the exact difference and is much more informative than the short failure message printed by the runner.
For detailed information, use WebFetch on these URLs: