首页 > 解决方案 > Laravel 没有在单元测试中引导 trait/authing 用户

问题描述

我不知道 Laravel 是否无法启动我的模型特征,或者根本没有看到用户在特征中被认证。

当我手动测试我的应用程序时,所有这些代码都可以正常工作,但是当我运行单元测试时,我遇到了一堆错误。

这是我添加的特征App\User和其他一些模型:

trait HasCompany
{
    public static function bootHasCompany()
    {
        if (auth()->check()) {
            static::creating(function ($model) {
                $model->company_id = auth()->user()->company_id;
            });
            static::addGlobalScope('company_id', function (Builder $builder) {
                $builder->where('company_id', auth()->user()->company_id);
            });
        }
    }

    public function company()
    {
        return $this->belongsTo('App\Company');
    }
}

此 trait 的目的是自动将登录用户添加company_id到他们创建的任何模型中,并限制他们仅访问他们创建的模型。我应该提到 all的数据库中App\User有一个company_id集合。

正如我所说,当我尝试在登录到我的应用程序时创建模型时,一切都很好。该特征完美地工作。然而,单元测试似乎并不关心这个特性。这是一个不起作用的示例测试:

class RoleTest extends TestCase
{
    use WithFaker;

    public $user;

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

        $this->user = App\User::create([
            'company_id' => $faker->randomNumber(),
            'name' => $this->faker->firstName,
            'email' => $this->faker->email,
            'password' => $this->faker->password,
        ]);
    }

    public function tearDown()
    {
        parent::tearDown();

        $this->user->delete();
    }

    public function testAdd()
    {
        $response = $this->actingAs($this->user)->json('POST', 'roles/add', [
            '_token' => csrf_token(),
            'name' => $this->faker->word,
        ]);

        $response->assertStatus(200)->assertJson(['flash' => true]);
    }
}

我得到的是 500 响应而不是 200 响应,因为模型应该自动获取company_idfrom $this->user,但事实并非如此。这仅发生在单元测试中。

这是模型代码:

class Role extends Model
{
    use HasCompany;

    protected $fillable = ['company_id', 'name'];  
}

为什么单元测试不能正确引导特征?似乎actingAs不适用于特征内的授权,或者无法完全启动它的特征。

标签: phplaravelunit-testing

解决方案


在您的单元测试中,用户模型是在 setup 函数创建用户时首先启动的。那时,没有用户被认证(如后面所见)。因此,auth()->check()仅在创建用户时发生一次。

我认为不是检查是否经过身份验证(在启动期间),您应该在用户创建期间检查是否经过身份验证。

从 bootHasCompany 中移除if(auth()->check())并将其添加到 Eloquent 事件闭包中,如下所示:

static::creating(function ($model) {
    if(auth()->check())
    {
        $model->company_id = auth()->user()->company_id;
    }
});
static::addGlobalScope('company_id', function (Builder $builder) {
    if(auth()->check())
    {
        $builder->where('company_id', auth()->user()->company_id);
    }
});

推荐阅读