symfony-testing — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited symfony-testing (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You are an expert in testing within Symfony hexagonal architecture.
| Topic | Rule | Versions |
|---|---|---|
| Test methods | test_ prefix or #[Test] attribute; never @test / @dataProvider doc-comments | annotations removed in PHPUnit 12 |
| Data providers | #[DataProvider('name')] + public static function name(): iterable | PHPUnit 10+ |
| Stubs vs mocks | createStub() for return values, createMock() only with expects() | PHPUnit 13 emits notices for mocks without expectations |
| Assertions | self::assert*() (static) | all |
| PHPUnit per PHP | 11 → PHP 8.2, 12 → PHP 8.3, 13 → PHP 8.4 | pick from the detected PHP version |
| PHPStan | 2.x, level 8 minimum (9-10 recommended for new code) | checkGenericClassInNonGenericObjectType removed in 2.0 |
| Foundry | 2.x: PersistentObjectFactory / ObjectFactory, defaults(), class() | ModelFactory was Foundry 1 |
tests/
├── Unit/
│ └── Domain/
│ └── {Module}/
│ ├── Entity/
│ │ └── {Entity}Test.php
│ └── ValueObject/
│ └── {ValueObject}Test.php
├── Integration/
│ └── Application/
│ └── {Module}/
│ ├── Command/
│ │ └── {Handler}Test.php
│ └── Query/
│ └── {Handler}Test.php
├── Functional/
│ └── Presentation/
│ └── {Module}/
│ └── API/
│ └── {Controller}Test.php
└── Support/
├── Adapter/
│ ├── InMemory{Entity}Repository.php
│ ├── SequentialIdGenerator.php
│ └── FakePasswordHasher.php
└── Factory/
└── {Entity}Factory.phpnamespace Tests\Unit\Domain\User\ValueObject;
use App\Domain\User\Exception\InvalidEmailException;
use App\Domain\User\ValueObject\Email;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
final class EmailTest extends TestCase
{
public function test_valid_email_is_created(): void
{
$email = new Email('[email protected]');
self::assertSame('[email protected]', $email->value);
}
#[DataProvider('invalidEmails')]
public function test_invalid_email_throws_exception(string $invalid): void
{
$this->expectException(InvalidEmailException::class);
new Email($invalid);
}
/** @return iterable<string, array{string}> */
public static function invalidEmails(): iterable
{
yield 'no at sign' => ['invalid'];
yield 'empty' => [''];
yield 'no domain' => ['user@'];
}
public function test_emails_are_equal(): void
{
self::assertTrue((new Email('[email protected]'))->equals(new Email('[email protected]')));
}
}namespace Tests\Integration\Application\User\Command;
use App\Application\User\Command\RegisterUser;
use App\Application\User\Command\RegisterUserHandler;
use App\Domain\User\ValueObject\UserId;
use PHPUnit\Framework\TestCase;
use Tests\Support\Adapter\FakePasswordHasher;
use Tests\Support\Adapter\InMemoryUserRepository;
use Tests\Support\Adapter\SequentialIdGenerator;
final class RegisterUserHandlerTest extends TestCase
{
public function test_it_registers_a_user(): void
{
$users = new InMemoryUserRepository();
$handler = new RegisterUserHandler($users, new FakePasswordHasher(), new SequentialIdGenerator());
$id = $handler(new RegisterUser('[email protected]', 'Test', 'password123'));
self::assertNotNull($users->findById(new UserId($id)));
}
}Prefer in-memory fakes over mocks for ports: tests then assert on state, not on call sequences, and survive refactoring.
namespace Tests\Functional\Presentation\User\API;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
final class UserControllerTest extends WebTestCase
{
public function test_create_user(): void
{
$client = static::createClient();
$client->loginUser(/* a SecurityUser with ROLE_USER_CREATE */);
$client->jsonRequest('POST', '/api/users', [
'email' => '[email protected]',
'name' => 'Test User',
'password' => 'Password123',
]);
self::assertResponseStatusCodeSame(201);
$response = json_decode((string) $client->getResponse()->getContent(), true, flags: JSON_THROW_ON_ERROR);
self::assertNotNull($response['result']['id']);
self::assertNull($response['error']);
}
}$client->jsonRequest() and $client->loginUser() work on every supported version. loginUser() authenticates through the test session, so it fits session-based firewalls; for a stateless token firewall, send a real token header (e.g. HTTP_AUTHORIZATION) instead.
See references/ for detailed guides:
test-organization.md - phpunit.xml.dist (PHPUnit 10-13), suites, PHPStan, CI, Foundry 2test-patterns.md - In-memory adapters, builders, Messenger transport assertions, functional patterns~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.