Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Phpunit Assertions Extension Laravel Package

behat/phpunit-assertions-extension

Behat extension that brings PHPUnit assertions into Behat step definitions, letting you use assertSame, assertTrue, and other familiar assertions in scenarios for clearer, more expressive test failures.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a thin bridge package, not a testing framework. It lets Behat step definitions use PHPUnit's static assertion API (PHPUnit\Framework\Assert) and reports assertion failures as normal failed Behat steps. For a Laravel codebase that already has PHPUnit installed, the useful part is PHPUnit's Assert; the extension is the Behat glue.

Check your current versions first:

composer show behat/behat phpunit/phpunit
vendor/bin/behat --version
vendor/bin/phpunit --version

Install and register it:

composer require --dev behat/phpunit-assertions-extension
# behat.yml
default:
  extensions:
    Behat\PHPUnit\Extension\PHPUnitAssertionsExtension: ~

A first, realistic use case is asserting a Laravel HTTP response inside a Behat context:

Feature: API health
  Scenario: health endpoint returns JSON
    When I request "/up"
    Then the response status should be 200
    And the JSON should contain key "status"
use Behat\Behat\Context\Context;
use PHPUnit\Framework\Assert;

final class ApiContext implements Context
{
    private $response;

    /** @When I request :path */
    public function iRequest(string $path): void
    {
        $this->response = $this->get($path); // assumes MakesHttpRequests setup
    }

    /** @Then the response status should be :status */
    public function responseStatusShouldBe(int $status): void
    {
        Assert::assertSame($status, $this->response->getStatusCode());
    }

    /** @Then the JSON should contain key :key */
    public function jsonShouldContainKey(string $key): void
    {
        Assert::assertArrayHasKey($key, $this->response->json());
    }
}

Run it with vendor/bin/behat features/api.feature. If the step fails, Behat prints PHPUnit's assertion message and marks the step failed.

Look first at the package README and its composer.json in vendor/behat/phpunit-assertions-extension/ to confirm supported Behat/PHPUnit ranges. Also test whether you actually need the extension: because PHPUnit is already autoloaded in most Laravel projects, PHPUnit\Framework\Assert often works directly in a Behat context. Keep the dependency only if the extension is doing something for your setup.

Implementation Patterns

Use static Assert calls directly. The day-to-day API is ordinary PHPUnit:

Assert::assertSame('active', $user->status);
Assert::assertTrue($response->isSuccessful());
Assert::assertArrayHasKey('id', $json);
Assert::assertStringContainsString('Welcome', $content);
Assert::assertJsonStringEqualsJsonString($expectedJson, $actualJson);

Always pass the optional message argument. Behat's step text is the only context a reader gets, so make the assertion self-explanatory.

Wrap domain assertions in a trait or base context. This keeps step definitions readable and makes later removal of the package easy:

trait ApiAssertions
{
    private function assertJsonPath(string $path, mixed $expected, array $json): void
    {
        Assert::assertSame(
            $expected,
            data_get($json, $path),
            "Expected JSON path [$path] to match."
        );
    }
}

Then use ApiAssertions; in your feature context.

Prefer Laravel's TestResponse assertions when you have them. If your Behat context uses Laravel's MakesHttpRequests trait and exposes a TestResponse, $response->assertOk(), $response->assertJsonPath(), and $response->assertJsonStructure() are already fluent and Laravel-aware. Use PHPUnit Assert for plain values, database state, or cases where no response assertion exists.

Use scenario outlines for data-driven cases. Behat does not use PHPUnit data providers. Put the table in the feature and assert each row:

Scenario Outline: status labels
  Given a user with status "<status>"
  Then the label should be "<label>"

  Examples:
    | status  | label   |
    | active  | Active  |
    | blocked | Blocked |

Use hooks for setup, assertions for checks. Bootstrap Laravel, refresh the database, or seed data in @BeforeScenario; keep assertions in the @Then steps. This extension does not bootstrap Laravel, manage transactions, or reset application state.

Consider a small injected assertion helper if contexts are services. Static calls are simplest, but a DomainAssertions service can be injected into contexts registered through behat.yml. That is useful when you want custom failure messages or shared assertions across several contexts.

Gotchas and Tips

Treat maturity as a risk. The package has very low adoption and explicitly says it is not recommended for new projects. Pin the version, keep usage behind a trait or helper, and be ready to remove it. For a new Laravel suite, prefer Pest/PHPUnit, or call PHPUnit\Framework\Assert directly if it already works in your Behat setup.

Check PHPUnit compatibility before adopting. PHPUnit 10/11 changed or removed some assertion APIs, and Behat extensions often lag behind. If Composer conflicts, either use a compatible PHPUnit line (for example PHPUnit 9.6 with Behat 3.x) or drop the extension and use the static Assert class directly.

expectException() is not available in Behat steps. Use try/catch plus Assert::fail():

try {
    $this->postJson('/api/orders', []);
    Assert::fail('Expected a validation exception.');
} catch (ValidationException $e) {
    Assert::assertArrayHasKey('email', $e->errors());
}

Do not catch \Throwable around assertions. You can swallow PHPUnit's AssertionFailedError and turn a failure into a pass. Catch only the specific domain exception you expect, then let assertion failures propagate.

A Behat context is not a PHPUnit TestCase. $this->assertSame() is not available unless you add it yourself. Use Assert::assertSame() or the response object's assertions. Extending PHPUnit\Framework\TestCase from a Behat context is a bad idea because the lifecycle and constructor expectations conflict.

Use verbose Behat output when debugging. PHPUnit's assertion diff can be truncated by formatters. Run vendor/bin/behat -vvv or switch to a more verbose formatter when you cannot see the expected/actual values.

Laravel database state is your responsibility. Behat does not automatically apply RefreshDatabase. Add hooks or a transaction wrapper; otherwise assertions will pass or fail based on leftover data.

Keep autoloading predictable. Ensure features/bootstrap/bootstrap.php requires vendor/autoload.php, and add any custom Behat namespace to composer.json followed by composer dump-autoload.

Prefer extension points over subclassing. Avoid extending PHPUnit\Framework\Assert; it is a static utility class and subclassing is brittle. Use a trait, helper service, or PHPUnit constraints (PHPUnit\Framework\Constraint\*) if you need custom matching logic.

Plan the removal path. Replacing Assert::assertSame($expected, $actual) with a small local helper or a native if ($expected !== $actual) { throw new RuntimeException(...); } is usually a one-file change. That makes this low-adoption package safe to trial and easy to drop.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource