phpunit - How do you test a Bus::chain()->catch() in laravel with php unit - Stack Overflow

I'm writing tests with phpunit to test some chained jobs are dispatched.I know how to use Bus::as

I'm writing tests with phpunit to test some chained jobs are dispatched. I know how to use Bus::assertChained() to verify that the expected jobs are chained.

What I'm struggling with is testing the catch() block in the event one of the chained jobs throws an exception.

For example:

Bus::chain([
    new JobOne($model),
    new JobTwo($model),
    new JobThree($model),
])
    ->catch(function (Throwable $e) use ($model) {
        $model->update([
            'error' => true,
        ]);
    })
    ->dispatch();

As the jobs are all new instances, they cannot be mocked to fake an exception being thrown, so how do I trigger the catch so I can assert that $model->error gets updated in the event of an exception?

I'm writing tests with phpunit to test some chained jobs are dispatched. I know how to use Bus::assertChained() to verify that the expected jobs are chained.

What I'm struggling with is testing the catch() block in the event one of the chained jobs throws an exception.

For example:

Bus::chain([
    new JobOne($model),
    new JobTwo($model),
    new JobThree($model),
])
    ->catch(function (Throwable $e) use ($model) {
        $model->update([
            'error' => true,
        ]);
    })
    ->dispatch();

As the jobs are all new instances, they cannot be mocked to fake an exception being thrown, so how do I trigger the catch so I can assert that $model->error gets updated in the event of an exception?

Share Improve this question asked 19 hours ago Dan BreakwellDan Breakwell 212 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

As the jobs are all new instances, they cannot be mocked to fake an exception being thrown

If you use the Container to make the job classes, you can add an arbitrary binding at run time in your tests. This is close to what the container does when you call the fake() methods in some facades.

More on binding:

  • https://laravel/docs/12.x/container#binding-instances
use App\Jobs\JobOne;
use App\Jobs\JobTwo;
use App\Jobs\JobThree;


Bus::chain([
    app()->make(JobOne::class, [$model]),
    app()->make(JobTwo::class, [$model]),
    app()->make(JobThree::class, [$model]),
])
    ->catch(function (Throwable $e) use ($model) {
        $model->update([
            'error' => true,
        ]);
    })
    ->dispatch();
#[Test]
public function catches_the_exception()
{
    // Make an anonymous class. Since jobs have all their logic in a handle method,
    // give this anonymous class a handle method that just fails with an Exception.
    $exceptionThrower = new class {
        public function handle()
        {
            throw new Exception;
        }
    };
    // Tell the container every time it gets asked to resolve JobOne,
    // it should instead return the anonymous class we just made.
    $this->app->instance(JobOne::class, $exceptionThrower);
    $model = ...;

    $job = $this->app->make(JobOne::class, [$model]);

    // Verify the container is replacing the job class
    $this->assertFalse($job instanceof JobOne);
    $this->assertTrue((new ReflectionClass($job))->isAnonymous());

    // Do whatever gets that Bus Chain going (using the sync driver)
    ...

    // Verify your catch block did something
    $this->assertEquals(true, $model->fresh()->error);
}

If app()->make(JobOne::class, [$model]) does not work, try passing in the parameter as an associative array with the same key names as you have in the constructor. For example if you have

class JobOne
{
    public function __construct($user) { ... }
    ...
}

Use it like app()->make(JobOne::class, ['user' => $model]).

And finally, if you don't like making calls to a global function, you can use a more class based approach too (it's the same result)

use Illuminate\Container\Container;

$container = Container::getInstance();
$container->make(JobOne::class, [$model]);

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1743763079a4502991.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信