Laravel事件分派Assert失败

6rqinv9w  于 2022-11-18  发布在  其他
关注(0)|答案(2)|浏览(146)

我正在写一些单元测试来测试一个数据库事务中间件,在一个异常的情况下,事务中的所有东西都应该回滚。这段代码工作得很好,并且通过了单元测试:

成功的公寓测试方法

public function testTransactionShouldRollback()
{
    Event::fake();

    // Ignore the exception so the test itself can continue.
    $this->expectException('Exception');

    $this->middleware->handle($this->request, function () {
        throw new Exception('Transaction should fail');
    });

    Event::assertDispatched(TransactionRolledBack::class);
}

然而,每当我测试TransactionBeginning事件时,它都无法Assert该事件已被调度。

失败的公寓测试方法

public function testTransactionShouldBegin()
{
    Event::fake();

    $this->middleware->handle($this->request, function () {
        return $this->response;
    });

    Event::assertDispatched(TransactionBeginning::class);
}

实际的中间件

public function handle($request, Closure $next)
{
    DB::beginTransaction();

    try {
        $response = $next($request);

        if ($response->exception) {
            throw $response->exception;
        }
    } catch (Throwable $e) {
        DB::rollBack();
        throw $e;
    }

    if (!$response->exception) {
        DB::commit();
    }

    return $response;
}

所有的事务事件都触发事件,所以DB::beginTransaction, DB::rollBack, DB::commit应该都触发事件。然而,当我测试时,我甚至只看到事务回滚事件触发。
在这种情况下,为什么其他事件没有触发,而我的assertDispatched失败了?

fnx2tebb

fnx2tebb1#

我不知道确切的原因(将不得不深入挖掘),但我找到了解决方案如何解决这个问题。
这里似乎仍然使用默认的事件调度程序,所以当你运行Event::fake()时,数据库连接使用默认的调度程序。

Event::fake();

要运行:

$fake = Event::fake();
DB::setEventDispatcher($fake);

经过这样的修改后,我的测试运行良好。下面是完整的测试用例类:

<?php

namespace Tests\Feature;

use App\Http\Middleware\TestMiddleware;
use Exception;
use Illuminate\Database\Events\TransactionBeginning;
use Illuminate\Database\Events\TransactionCommitted;
use Illuminate\Database\Events\TransactionRolledBack;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * @var \App\Http\Middleware\TestMiddleware
     */
    protected $middleware;

    /**
     * @var \Illuminate\Http\Request
     */
    protected $request;

    /**
     * @var \Illuminate\Http\Response
     */
    protected $response;

    public function setUp():void
    {
        parent::setUp();

        Event::fake();

        $this->middleware = new TestMiddleware();

        $this->request = new Request();

        $this->response = new Response();
    }

    public function testTransactionShouldRollback()
    {
        $fake = Event::fake();
        DB::setEventDispatcher($fake);

        // Ignore the exception so the test itself can continue.
        $this->expectException('Exception');

        $this->middleware->handle($this->request, function () {
            throw new Exception('Transaction should fail');
        });

        Event::assertDispatched(TransactionBeginning::class);
        Event::assertDispatched(TransactionRolledBack::class);
        Event::asserNotDispatched(TransactionCommitted::class);
    }

    public function testTransactionShouldBegin()
    {
        $fake = Event::fake();
        DB::setEventDispatcher($fake);

        $this->middleware->handle($this->request, function () {
            return $this->response;
        });

        Event::assertDispatched(TransactionBeginning::class);
        Event::assertNotDispatched(TransactionRolledBack::class);
        Event::assertDispatched(TransactionCommitted::class);
    }
}
oewdyzsn

oewdyzsn2#

使用另一个答案,这使事情工作到我发现在测试或代码的其他地方有错误的地步。
当我修复了不相关的错误时,我能够切换回Event::fake()。
有关详细信息,请参阅此处:
https://github.com/laravel/framework/issues/18923#issuecomment-1311520190

相关问题