Skip to content
Latchkey

PHPUnit "risky" Tests & Deprecations-as-Errors Fail the Build

PHPUnit can mark tests "risky" - no assertions, unexpected output, or leaked global state - and with failOnRisky/failOnDeprecation enabled those, plus deprecation notices, fail the build even though no assertion actually failed.

What this error means

CI fails with "This test did not perform any assertions," "Test code or tested code printed unexpected output," or a deprecation summary, while the test bodies themselves did not assert-fail. The strictness flags promoted warnings to failures.

PHPUnit output
1) App\Tests\CartTest::testTotals
This test did not perform any assertions

OK, but there were issues!
Tests: 12, Assertions: 30, Risky: 1, Deprecations: 4.

Common causes

Test performs no assertions

A test that exercises code but never calls an assertion is "risky" - it proves nothing. With failOnRisky (or beStrictAboutTestsThatDoNotTestAnything) it fails.

Deprecations promoted to failures

failOnDeprecation/failOnWarning turn PHP or library deprecation notices into build failures, so code calling a deprecated API fails CI even if behavior is correct.

Unexpected output or global state leak

Echoing output or mutating globals/superglobals during a test makes it risky under strict mode.

How to fix it

Assert something, or mark intentionally assertion-free tests

Add a real assertion; if a test only verifies "no exception," use expectNotToPerformAssertions() to declare that intent.

CartTest.php
public function testBootsWithoutError(): void
{
    $this->expectNotToPerformAssertions();
    new Kernel('test', true); // throws on failure
}

Address deprecations or scope the strictness

  1. Fix the deprecated API calls the deprecation summary lists.
  2. Keep failOnRisky/failOnDeprecation on, but track deprecations to migrate them deliberately.
  3. Avoid echo/output and global mutation inside tests to clear "risky" flags.

How to prevent it

  • Ensure every test makes at least one assertion (or declares it makes none).
  • Keep dependencies current so deprecation notices stay low.
  • Run with strict flags locally so risky tests surface before CI.

Frequently asked questions

What causes ""risky test" / deprecations fail"?
A test that exercises code but never calls an assertion is "risky" - it proves nothing. With failOnRisky (or beStrictAboutTestsThatDoNotTestAnything) it fails.
How do I fix "risky test" / deprecations fail?
Add a real assertion; if a test only verifies "no exception," use expectNotToPerformAssertions() to declare that intent.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card