---
title: "Testovanie — Two-Factor for Laravel | Roundly"
description: "TwoFactor::fake() nasadí programovateľného dvojníka bez kryptografie, ktorý zaznamená každé volanie — alebo testujte skutočné kódy pri zmrazenom čase."
url: https://roundly-consulting.com/sk/open-source/navody/two-factor-for-laravel/testovanie
language: sk
---

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

[Two-Factor for Laravel](https://roundly-consulting.com/sk/open-source/navody/two-factor-for-laravel.md)

# Testovanie

TwoFactor::fake() nahradí službu programovateľným dvojníkom bez kryptografie a vráti ho ako TwoFactorFake na asercie. Vidí ho fasáda, vložený TwoFactorService aj metódy modelu, takže tok 2FA otestujete bez zmrazovania času a bez výpočtu skutočných kódov:

```php
use RoundlyConsulting\TwoFactor\Enums\TwoFactorMethod;
use RoundlyConsulting\TwoFactor\Facades\TwoFactor;

// attempt() only passes a user with confirmed 2FA, as in production. Enrol them first:
// under the fake, enrolment runs for real on its canned secret and accepts any code.
TwoFactor::fake();
TwoFactor::for($user)->start();
TwoFactor::for($user)->confirm('123456');

// Accept any code (the default) and assert the challenge was verified:
$fake = TwoFactor::fake()->accept();
$this->post('/login/2fa', ['code' => '123456'])->assertOk();
$fake->assertVerifiedFor($user);

// Reject every code:
TwoFactor::fake()->reject();
$this->post('/login/2fa', ['code' => '000000'])->assertStatus(422);

// Accept only a specific code:
TwoFactor::fake()->acceptCode('424242');

// Drive attempt(): pass via a recovery code, report 2 left, assert the method:
$fake = TwoFactor::fake()->acceptRecoveryCode()->withRemainingRecoveryCodes(2);
$this->post('/login/2fa', ['code' => 'ABCDE-12345'])->assertOk();
$fake->assertVerifiedVia(TwoFactorMethod::RecoveryCode);

// Fail as a replay (VerificationResult::$replayed === true):
TwoFactor::fake()->replay();

// Enrolment writes run for real on the fake's canned secret and codes, and are recorded:
$fake = TwoFactor::fake();
$this->post('/two-factor/disable')->assertOk();       // or $user->disableTwoFactor()
$this->post('/two-factor/enable')->assertOk();        // calls TwoFactor::for($user)->start()
$fake->assertDisabled($user);
$fake->assertStarted($user);
$fake->assertNothingRegenerated();
```

## Čo fake robí

- attempt() nepočíta žiadnu TOTP matematiku — vráti naprogramovaný výsledok a zaznamená používateľa, kód aj výsledok.
- Rovnako ako skutočná akcia, attempt() odmietne používateľa bez potvrdeného 2FA bez ohľadu na naprogramovaný výsledok — bez udalosti a bez spotreby kódu — takže test nemôže prejsť na niečom, čo by produkcia odmietla. Používateľa preto najprv aktivujte cez start() a confirm() pod fake, ktorý prijme akýkoľvek kód.
- Pre aktivovaného používateľa attempt() vyvolá tie isté udalosti ako skutočná akcia — TwoFactorVerified, RecoveryCodeConsumed, TwoFactorVerificationFailed a TwoFactorReplayDetected (s časovým krokom 0) — a úspech cez záložný kód spotrebuje jeden uložený kód, takže status() zodpovedá výsledku. Kód zadaný s medzerami či pomlčkami sa počíta ako jeho číslice, rovnako ako v skutočnej akcii.
- start(), confirm(), recoveryCodes()->regenerate() a disable() stále spúšťajú skutočné akcie, no nad pripraveným tajným kľúčom a záložnými kódmi fake a jeho programovateľným verify(); zaznamenajú sa až po úspechu — neúspešné potvrdenie sa nezaznamená.
- status() a recoveryCodes()->remaining() čítajú priamo z modelu.

## Programovateľné správanie

| Metóda | Účinok |
| --- | --- |
| `accept()` | Každé verify() aj attempt() prejde cez TOTP (predvolené) — attempt() však používateľa bez potvrdeného 2FA stále odmietne. |
| `acceptRecoveryCode()` | attempt() prejde cez záložný kód a spotrebuje jeden uložený kód (prvý). |
| `reject()` | Každé verify() aj attempt() zlyhá. |
| `replay()` | attempt() zlyhá ako opakovanie (replayed: true). |
| `acceptCode($code)` | Prijme len presne tento kód, cez aktuálnu metódu. |
| `withRemainingRecoveryCodes($n)` | Pevne nastaví hlásený počet. Bez neho fake hlási uložený počet používateľa, o jeden nižší, keď prejde záložný kód. Uložený kód sa spotrebuje v oboch prípadoch. |
| `withSecret($secret)` | Tajný kľúč, ktorý vráti generateSecret(). |
| `withRecoveryCodes(...$codes)` | Kódy, ktoré vráti generateRecoveryCodes(). |

## Asercie

Všetky asercie na vrátenom fake. Argument $user je pri assertStarted(), assertConfirmed(), assertRegenerated() a assertDisabled() voliteľný:

| Asercia | Prejde, keď |
| --- | --- |
| `assertVerified()` | Aspoň jedno attempt() prešlo. |
| `assertVerifiedFor($user)` | Pre tohto používateľa prešlo attempt(). |
| `assertVerifiedVia(TwoFactorMethod::RecoveryCode)` | attempt() prešlo cez túto TwoFactorMethod. |
| `assertVerificationFailed()` | Aspoň jedno attempt() zlyhalo. |
| `assertVerifyCount(2)` | Zaznamenal sa presne tento počet volaní attempt(). |
| `assertCodeAttempted('424242')` | Tento kód prešiel cez attempt() alebo plochú verify(). |
| `assertNothingVerified()` | Nezaznamenalo sa žiadne attempt(). |
| `assertStarted($user)` | start() uspelo — pre tohto používateľa, ak ho zadáte. |
| `assertNothingStarted()` | Nespustila sa žiadna aktivácia. |
| `assertConfirmed($user)` | confirm() uspelo — neúspešné potvrdenie sa nezaznamenáva. |
| `assertNothingConfirmed()` | Nepotvrdila sa žiadna aktivácia. |
| `assertRegenerated($user)` | Prebehlo recoveryCodes()->regenerate() — pre tohto používateľa, ak ho zadáte. |
| `assertNothingRegenerated()` | Žiadne záložné kódy sa neobnovili. |
| `assertDisabled($user)` | Prebehlo disable() — pre tohto používateľa, ak ho zadáte. |
| `assertNothingDisabled()` | 2FA sa nikomu nevyplo. |

Celý test overenia pri prihlásení s aserciami overovania:

```php
use RoundlyConsulting\TwoFactor\Enums\TwoFactorMethod;
use RoundlyConsulting\TwoFactor\Facades\TwoFactor;

it('lets the user through with the right code only', function (): void {
    $user = User::factory()->create();

    // attempt() only passes a user with confirmed 2FA — enrol under a first fake:
    TwoFactor::fake();
    TwoFactor::for($user)->start();
    TwoFactor::for($user)->confirm('123456');

    $fake = TwoFactor::fake()->acceptCode('424242');

    $this->actingAs($user)->post('/login/2fa', ['code' => '000000'])->assertStatus(422);
    $this->actingAs($user)->post('/login/2fa', ['code' => '424242'])->assertOk();

    $fake->assertVerifyCount(2);
    $fake->assertCodeAttempted('000000');
    $fake->assertVerificationFailed();
    $fake->assertVerified();
    $fake->assertVerifiedFor($user);
    $fake->assertVerifiedVia(TwoFactorMethod::Totp);
    $fake->assertNothingStarted();
    $fake->assertNothingConfirmed();
    $fake->assertNothingDisabled();
});
```

Asercie vyhadzujú TwoFactorAssertionFailedException — výnimku balíka, nie PHPUnit asserciu — takže fungujú v akomkoľvek test runneri. Fake je určený len na testy: registruje sa výlučne cez TwoFactor::fake() a nikdy nie v produkcii.

## Testovanie so skutočnými kódmi

Ak chcete otestovať skutočnú kryptografiu, zmrazte čas cez Carbon::setTestNow() a aktuálny kód vypočítajte cez TwoFactor::currentCode():

```php
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Event;
use RoundlyConsulting\TwoFactor\Events\TwoFactorConfirmed;
use RoundlyConsulting\TwoFactor\Events\TwoFactorReplayDetected;
use RoundlyConsulting\TwoFactor\Facades\TwoFactor;

it('rejects the confirmation code replayed at first login', function (): void {
    Carbon::setTestNow(Carbon::createFromTimestamp(1_700_000_000));
    Event::fake();

    $user = User::factory()->create();
    $setup = TwoFactor::for($user)->start();
    $code = TwoFactor::currentCode($setup->secret);

    TwoFactor::for($user->fresh())->confirm($code);

    expect(TwoFactor::for($user->fresh())->status()->enabled)->toBeTrue();
    Event::assertDispatched(TwoFactorConfirmed::class);

    // The exact code used to confirm cannot double as the first login code.
    expect(TwoFactor::for($user->fresh())->attempt($code)->verified)->toBeFalse();
    Event::assertDispatched(TwoFactorReplayDetected::class);

    // A code at a later timestep still verifies.
    Carbon::setTestNow(Carbon::createFromTimestamp(1_700_000_060));
    expect(TwoFactor::for($user->fresh())->attempt(TwoFactor::currentCode($setup->secret))->verified)->toBeTrue();

    Carbon::setTestNow();
});
```

## 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/two-factor-for-laravel.md)
