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 Json Rpc Laravel Package

tourze/phpunit-json-rpc

A PHPUnit extension for testing JSON-RPC services. It helps PHP developers send requests, validate responses, and assert protocol behavior in automated test suites, making JSON-RPC API integration testing simpler and more reliable.

View on GitHub
Deep Wiki
Context7

Getting Started

tourze/phpunit-json-rpc ships as a dev-only dependency that gives PHPUnit assertions for JSON-RPC 2.0 envelopes, so you spend less time hand-writing assertArrayHasKey('result', ...) boilerplate.

composer require --dev tourze/phpunit-json-rpc:^1.0

1.0.0 is the first tagged stable release — the changelog link contains no migration notes, which means there is no previous API to break from, but it also means the surface is freshly frozen. Treat ^1.0 as your constraint and read src/ before assuming method names; the package is small enough to audit in a few minutes.

Where to look first, in order:

  1. README.md — usually the only prose documentation for Tourze packages.
  2. src/ — the assertion trait / base test case and its public method signatures. This is the real API reference.
  3. tests/ — the package's own tests double as usage examples you can copy verbatim.

First use case — assert a successful call end-to-end against a Laravel route:

use Tourze\PHPUnitJsonRpc\JsonRpcAssertions; // verify exact namespace in src/

class RpcTest extends TestCase
{
    use JsonRpcAssertions;

    public function test_ping(): void
    {
        $response = $this->postJson('/rpc', [
            'jsonrpc' => '2.0',
            'method'  => 'system.ping',
            'params'  => [],
            'id'      => 1,
        ]);

        $response->assertOk();
        $this->assertJsonRpcResult($response->json(), expected: 'pong');
    }
}

If the trait's helpers don't match your naming instincts, wrap them in a project-local BaseRpcTestCase on day one — see below.

Implementation Patterns

Envelope assertion, not payload assertion. The core value of a JSON-RPC assertion library is enforcing the shape: jsonrpc === "2.0", presence of exactly one of result / error, and id echo. Structure your tests so the library checks the envelope and a plain assertSame checks your domain value. Mixing the two makes failures ambiguous.

Base test case as the integration seam. Rather than use-ing the trait in every test class, create one abstract RpcTestCase in tests/ that applies the trait, defines a rpc(string $method, array $params = [], int|string|null $id = 1) helper posting to your endpoint, and exposes your auth/tenant setup. Every RPC test then extends that. This is where you absorb any API churn from a 1.x minor release in one place.

Data providers for method matrices. JSON-RPC endpoints are naturally table-driven — same transport, many methods. Put [method, params, expectedResult] tuples in a provider and assert the envelope once per case. This keeps coverage broad without duplicating setup.

Error-path pattern. For each documented error code, assert both the code and the absence of result. A response containing both result and error is spec-invalid but will pass a naive "has error key" check — assert mutual exclusivity explicitly, ideally via the package's error assertion plus a assertArrayNotHasKey('result', ...).

Batch requests. For [{...}, {...}], remember the spec does not guarantee response ordering; the spec only requires each response carry the id of its request. Sort by id (or map by id) before asserting. If the package offers a batch helper, confirm whether it sorts for you — read the source rather than trusting the name.

Notification coverage. Methods invoked without id must produce an empty body (HTTP 204 or 200 with no content). These are easy to forget and are a common source of production-only bugs; add one test per notification-capable method.

Contract testing against a schema. If you already maintain an OpenAPI/JSON Schema for the RPC surface, layer the package's envelope assertions underneath a schema validation of result. The two are complementary: schema catches payload drift, this package catches protocol drift.

Gotchas and Tips

  • id type fidelity. The spec requires the response id to be the same JSON type as the request. "1" and 1 are different. Use assertSame, never assertEquals, or a coercion bug in your handler will slip through.
  • result: null vs absent result. A valid response may legitimately have result: null for a void method. assertArrayHasKey is the correct check; isset() is not.
  • Empty object vs empty array. PHP's json_encode([]) yields [], but JSON-RPC params/results often require {}. If your assertions decode to arrays, this distinction collapses and you cannot test it. Assert on the raw body string where it matters.
  • HTTP 200 for errors. JSON-RPC errors are application-level, not transport-level. Do not assert 4xx/5xx on an RPC error response; assert assertOk() and then the error envelope. A 422 usually means Laravel's validation layer rejected the request before your RPC handler saw it — a different bug class worth its own test.
  • PHPUnit major-version coupling. Tourze packages frequently pin phpunit/phpunit in require-dev and occasionally in require. Check composer.json before installing into a Laravel 11/12 app on PHPUnit 10/11 — a hard ^9 constraint will force a resolution conflict or a downgrade. If it conflicts, composer require --dev -W and inspect what it wants to move.
  • Trait vs base class. If the package offers both, prefer the trait: it composes with your existing Tests\TestCase and avoids fighting Laravel's bootstrap. The base class is only worth it if the package does its own setUp work you need.
  • Debugging envelope failures. When an assertion fails with a terse message, dump $response->getContent() (raw, not ->json()) — decoded arrays hide key-ordering, duplicate keys, and numeric precision issues that the raw string reveals.
  • Float precision in result. assertEquals on floats is fragile. Compare with an epsilon, or compare the string form. This bites most often on financial/timestamp results.
  • Extension point. Because these assertion libraries are thin, the practical extension point is composition, not inheritance: write your own assertRpcError(int $code, ?string $message = null) that delegates to the package and adds your project's conventions (e.g. asserting data.trace_id is present). Keep it in the base test case.
  • 1.0.0 with no changelog detail. The release notes are an empty changelog link. For a fresh 1.0 this is normal (there is nothing to summarize), but it means you are the first line of defence: pin the exact version in composer.lock, and re-read src/ on any 1.x bump before letting CI pull it. Watch the repo for a 1.0.1 — first stable releases of small packages commonly collect immediate patch fixes.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums