---
title: "Testovanie — Webhooks for Laravel | Roundly"
description: "Webhooks::fake() so všetkými overeniami a ich negáciami, SignedWebhookRequest pre testy príjmu v akejkoľvek schéme, factories a FakeHostResolver pre DNS."
url: https://roundly-consulting.com/sk/open-source/navody/webhooks-for-laravel/testovanie
language: sk
---

[Všetky balíky](https://roundly-consulting.com/sk/open-source.md)

[Webhooks for Laravel](https://roundly-consulting.com/sk/open-source/navody/webhooks-for-laravel.md)

# Testovanie

## Webhooks::fake()

```php
use RoundlyConsulting\Webhooks\Facades\Webhooks;
use RoundlyConsulting\Webhooks\Testing\SentWebhook;

$fake = Webhooks::fake();

$sendInvoiceWebhook($invoice);   // your code calls Webhooks::send() / broadcast() / …

$fake->assertSent($endpoint, 'invoice.paid', fn (array $payload): bool => $payload['invoice'] === 42);
$fake->assertSent('invoice.paid', payload: fn (array $payload): bool => $payload['invoice'] === 42);   // without the endpoint
$fake->assertSent(fn (SentWebhook $sent): bool => $sent->endpoint->is($endpoint) && ! $sent->broadcast);
$fake->assertSentTimes(1, 'invoice.paid');
$fake->assertNotSent($otherEndpoint);
$fake->assertBroadcast('invoice.paid', $team, fn (array $payload): bool => $payload['invoice'] === 42);
$fake->assertBroadcastTimes(1, 'invoice.paid');
$fake->assertNotBroadcast('invoice.void');
```

Každé zaznamenané sloveso má overenie aj jeho negáciu:

| Sloveso | Overenie | Negácie | Kolekcia |
| --- | --- | --- | --- |
| `send()` | assertSent($endpoint\|$type\|Closure, ?$type, ?$payload), assertSentTimes($n, …) | assertNotSent(…), assertNothingSent() | sent() — SentWebhook: endpoint, eventType, payload, body, broadcast, owner, webhookId |
| `broadcast()` | assertBroadcast($type, ?$owner, ?$payload), assertBroadcastTimes($n, $type, ?$owner, ?$payload) | assertNotBroadcast($type, ?$owner), assertNothingBroadcast() | broadcasts() — RecordedBroadcast: eventType, owner, payload |
| `redeliver() · redeliverFailed()` | assertRedelivered($delivery\|$endpoint) | assertNothingRedelivered() | redelivered() |
| `replay()` | assertReplayed($delivery) | assertNothingReplayed() | replayed() |
| `rotateSecret()` | assertSecretRotated($endpoint) | assertSecretNotRotated($endpoint), assertNoSecretsRotated() | — |
| `disable()` | assertEndpointDisabled($endpoint) | assertEndpointNotDisabled($endpoint), assertNoEndpointsDisabled() | — |

- send(), broadcast(), ping(), redeliver(), redeliverFailed() a replay() overujú presne ako v produkcii — vypnuté endpointy alebo endpointy bez odberu, chybné typy udalostí, príliš veľký obsah, práve spracúvané či vyčistené doručenia vyhodia rovnaké výnimky — no nič nezaradia, nič neodošlú a nezapíšu žiadne doručenie.
- Fake send() vráti neuložené OutboundDelivery: exists je false a getKey() je null — porovnávajte jeho webhookId() (msg\_…). redeliverFailed() vráti počty, ktoré by produkcia zaradila a preskočila.
- Správa endpointov, receive() a verify() bežia naozaj; rotácie kľúčov a disable() bežia naozaj a zároveň sa zaznamenajú. dispatchDue() — a teda webhooks:retry — nič neodošle a vráti 0.
- Broadcast zaznamená aj SentWebhook pre každý endpoint, ktorý ho prijme (broadcast: true); ping() sa zaznamená ako odoslanie webhook.ping; opakovanie idempotentného odoslania sa znova nezaznamená.
- Fake rozširuje manažér, takže aj injektovaný WebhooksManager je fake, a vidí volania cez inbound(), outbound(), for($owner), trait HasWebhooks aj udalosti BroadcastsAsWebhook. Prežije reset scope, takže test so skutočným queue:work stále komunikuje s tým istým fake.

## SignedWebhookRequest — prichádzajúce požiadavky pre testy

```php
use RoundlyConsulting\Webhooks\Testing\SignedWebhookRequest;

SignedWebhookRequest::for($endpoint)
    ->payload(['type' => 'invoice.paid', 'data' => ['id' => 42]])   // or ->body('exact bytes')
    ->send()                                                          // through the HTTP kernel: TestResponse
    ->assertAccepted();

SignedWebhookRequest::for($endpoint)->tamper()->send()->assertUnauthorized();
SignedWebhookRequest::for($endpoint)->staleBy(600)->send()->assertUnauthorized();
SignedWebhookRequest::for($endpoint)->unsigned()->send()->assertUnauthorized();                 // missing_signature
SignedWebhookRequest::for($endpoint)->withoutHeader('webhook-timestamp')->send()->assertUnauthorized();
SignedWebhookRequest::for($endpoint)->idempotencyKey('order-7')->send();
SignedWebhookRequest::for($rotatedEndpoint)->signedWithPrevious()->send();   // rotation grace
SignedWebhookRequest::for($endpoint)->id('msg_1')->at($instant)->secret('whsec_…')->withHeader('X-A', 'b');
SignedWebhookRequest::for($rfc9421Endpoint)->keyId('partner')->send();     // signed by sentinel
$data = SignedWebhookRequest::for($endpoint)->toRequest();                    // SignedRequestData: uri, headers, body
$this->call('POST', $data->uri, [], [], [], $data->server(), $data->body);    // your own call
```

Podpisuje vlastnou schémou endpointu: predvolenou schémou, akoukoľvek schémou implementujúcou SignsOutboundWebhooks (recepty github a stripe ju implementujú), alebo — pri schéme bez sign() — closure, ktorú zadáte. Inak toRequest() vyhodí LogicException s názvom schémy; nikdy nepošle hlavičky, ktoré by schéma neprijala.

```php
SignedWebhookRequest::for($endpoint)
    ->signUsing(fn (OutgoingWebhook $message, EndpointSecrets $secrets): SignatureHeaders => new SignatureHeaders([/* … */]))
    ->send();
```

tamper() pri predvolenej schéme a RFC 9421 zmení bajt podpisu, pri ostatných podpísané telo. signedWithPrevious() na endpointe bez predchádzajúceho kľúča vyhodí LogicException, rovnako ako endpoint RFC 9421 bez keyId() aj bez scheme\_options.key\_id.

## Factories

Každý model balíka má factory a každá vytvára nakonfigurovanú triedu modelu, takže vymenený model dostane vlastné inštancie:

| Factory | Stavy |
| --- | --- |
| `InboundEndpoint::factory()` | withSecret(string $secret), disabled(), scheme(string $scheme), handler(string $alias), ownedBy(Model $owner) |
| `OutboundEndpoint::factory()` | url(string $url), subscribedTo(array $types), withSecret(string $secret), withHeaders(array $headers), disabled(), ownedBy(Model $owner) |
| `OutboundDelivery::factory()` | status(OutboundStatus $status) |
| `InboundDelivery::factory() · OutboundAttempt::factory()` | — |

```php
$endpoint = InboundEndpoint::factory()->handler('billing')->ownedBy($team)->create();
$outbound = OutboundEndpoint::factory()->url('https://hooks.example.com/in')->subscribedTo(['invoice.*'])->create();
$failed = OutboundDelivery::factory()->status(OutboundStatus::Failed)->create();
```

Odchádzajúci endpoint z factory pri uložení preskočí kontrolu SSRF — jeho URL sa preloží až pri pokuse. Na tieto preklady odpovedzte cez FakeHostResolver.

## DNS pre testy odosielania

```php
use RoundlyConsulting\Webhooks\Testing\FakeHostResolver;

$dns = FakeHostResolver::map(['hooks.example.com' => '93.184.216.34'])->install();   // = SafeFetch::fakeDns()
Http::fake(['*' => Http::response('ok')]);
```

FakeHostResolver::map(array $records) prijíma hostiteľ ⇒ jedna adresa alebo zoznam (A aj AAAA); install() vráti [fake resolver zo Safe Fetch](https://roundly-consulting.com/sk/open-source/navody/safe-fetch-for-laravel/testovanie.md) s jeho overeniami (assertLookedUp($host, $times)). Meno, ktoré tabuľka nepozná, sa nepreloží, takže test sa nikdy nedostane k skutočnému DNS. Laravel odovzdá stubu Http::fake() voľby požiadavky, takže test vidí aj pripnutie:

```php
Http::fake(fn (Request $request, array $options) => Http::response($options['curl'][CURLOPT_RESOLVE][0]));
```

## Registre a fake Sentinelu

Schémy a handlery registrované za behu platia pre celý proces; v teste ich odstránite (nakonfigurované ostanú):

```php
Webhooks::schemes()->forget('github');
Webhooks::handlers()->forget('billing');
```

Pri [Sentinel::fake()](https://roundly-consulting.com/sk/open-source/navody/sentinel-for-laravel/testovanie.md) overenie prichádzajúcich a podpis odchádzajúcich správ zaznamenajú verifyWithSecrets a signWithSecret — nikdy tajný kľúč — a vypočítajú skutočný výsledok; deduplikácia sa správa tak ako fake Sentinelu.

## Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

[Ďalšie spôsoby podpory vrátane kryptomien](https://roundly-consulting.com/sk/podporte-nas.md)

Odoslaním daru súhlasíte s našimi [podmienkami prijímania darov](https://roundly-consulting.com/sk/podmienky-darov.md).

[Podporte našu open-source prácu (otvorí sa v novej karte)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Pridajte sa k nám na Patreone (otvorí sa v novej karte)](https://www.patreon.com/cw/roundly)

## Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.

[Ponuka do 48 hodín](https://roundly-consulting.com/sk/kontakt.md) [Prezrieť všetky balíky](https://roundly-consulting.com/sk/open-source/navody/webhooks-for-laravel.md)
