'Laravel actingAs guest
Laravel provides a way to authenticate a given user during HTTP testing with
$this->actingAs($user);
Is there a way to unauthenticate that $user within the same test?
Solution 1:[1]
Yes, you can unauthenticate using this:
Auth::logout();
https://laravel.com/docs/7.x/authentication#logging-out
Warning: above does far more than just forgetting (acting as if the login did not happen), for example, when using JWT above should invalidate token.
Solution 2:[2]
Yes, define new actingAsGuest method in base TestCase class
in file tests/TestCase.php
<?php
namespace Tests;
use Illuminate\Auth\RequestGuard;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;
    
    protected function setUp(): void
    {
        parent::setUp();
        // add logout method to RequestGuard
        RequestGuard::macro('logout', function() {
            $this->user = null;
        });
    }
    // add method to base TestCase class
    public function actingAsGuest(): void
    {
        $this->app['auth']->logout();
    }
}
And then in your test class you can use it:
<?php
namespace Tests\Feature;
use App\Models\User;
use Tests\TestCase;
class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function test_example()
    {
        // acting as authenticated user
        $this->actingAs(User::factory()->create());
        $this->assertAuthenticated();
        
        // acting as unauthenticated user
        $this->actingAsGuest();
        $this->assertGuest();
    }
}
    					Solution 3:[3]
I had same requirements as OP did, but wanted actingAsGuest() to completely reset everything, except Database state.
Full App reset (except DB)
For Laravel 7 (and maybe newer or older)
I toke a look at Laravel's tearDown() and setUp() methods.
And came up with helper method like:
use Illuminate\Support\Facades\Facade;
// ...
function actingAsGuest()
{
    // Backup database state.
    /** @var \Illuminate\Database\MySqlConnection $connection */
    $connection = app('db.connection');
    // Reset everything else.
    /** @var \Illuminate\Foundation\Application $app */
    $app = $this->app;
    $app->flush();
    $this->app = null;
    Facade::clearResolvedInstances();
    $this->refreshApplication();
    // Restore database state.
    app('db')->extend($connection->getName(), function () use ($connection) {
        return $connection;
    });
}
WARNING !!
Above works fine unless your test's logic caches any of above discarded objects somewhere.
For example, Laravel's DatabaseTransactions trait did cache db facade (in their App-Destroyed-listener).
Which we fixed by overriding said trait's logic.
Like we changed:
// ... $this->beforeApplicationDestroyed(function () use ($database) { // ...Into:
// ... $this->beforeApplicationDestroyed(function () { $database = app('db'); // ...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | Top-Master | 
| Solution 2 | Lukas Pierce | 
| Solution 3 | 
