tkaratug/eloquent-scope-assertion

Eloquent作用域断言,用于测试Laravel应用程序。

1.2.0 2023-02-19 14:55 UTC

This package is auto-updated.

Last update: 2024-09-19 18:22:07 UTC


README

Latest Version on Packagist Total Downloads

此包允许您在测试中断言模型作用域被调用。

安装

您可以通过composer安装此包

composer require tkaratug/eloquent-scope-assertion

用例

假设您有一个复杂的条件查询,用于Orders,并将其导入进行测试。

  • 获取尚未付款的订单。
  • 按创建日期降序排序。
  • 列表可以继续。

上述查询约束应在功能级别进行测试,因此您将拥有以下测试;

  • user_can_get_orders
  • user_can_get_only_unpaid_orders
  • user_can_get_orders_by_created_at_desc
  • 列表可以继续。

由于查询发生在模型作用域中,因此最好在模型的单元测试中测试该查询,因此只需编写一次测试覆盖率。

然而,在您的功能测试中,很难确定具有测试覆盖率的模型作用域实际上是否在控制器中使用,因此您可能会以某种方式在功能测试中重复该测试覆盖率。因此,您编写的单元测试几乎没有意义。

为此,此包在调用模型作用域时触发一个包含作用域名称和模型的名称的事件。这样,在功能测试中很容易断言事件是否以正确的作用域和模型名称触发。

用法

HasScopeAssertion特性添加到TestCase类中,以便在功能测试中调用assertScopeCalled()方法。

由于ModelScopeCalled事件在调用命名作用域时触发,因此您应该在setUp()方法中模拟它。

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Tkaratug\EloquentScopeAssertion\Traits\HasScopeAssertion;
use Illuminate\Support\Facades\Event;
use App\Events\ModelScopeCalled;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;
    use HasScopeAssertion;

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

        Event::fake([ModelScopeCalled::class]);
    }
}

然后在您的模型中添加HasScopeWatcher特性,以便能够断言其作用域。

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Tkaratug\EloquentScopeAssertion\Traits\HasScopeWatcher;

class Order extends Model
{
    use HasFactory;
    use HasScopeWatcher;

    public function scopeUnpaid(Builder $query): Builder
    {
        return $query->where('is_paid', false);
    }

    public function scopeCreatedAtDesc(Builder $query): Builder
    {
        return $query->latest('created_at');
    }
}

假设您只想查看按创建日期降序排序的未付款订单。

OrderController应如下所示;

use App\Models\Order;
use App\Http\Resources\OrderResource;

public OrderController extends Controller
{
    public function index(): void
    {
        $orders = Order::query()
                       ->unpaid()
                       ->createdAtDesc()
                       ->get();

        return OrderResource::collection($orders);
    }
}

现在您可以简化OrderControllerTest中的测试覆盖率,如下所示;

use App\Models\Order;
use Illuminate\Database\Eloquent\Factories\Sequence;

class OrderControllerTest extends TestCase
{
    public function user_can_get_unpaid_orders_sorted_by_creation_date_descenting(): void
    {
        Order::factory()
             ->unpaid()
             ->createMany([
                 ['created_at' => Carbon::parse('7 days ago')],
                 ['created_at' => Carbon::parse('14 days ago')],
                 ['created_at' => Carbon::parse('21 days ago')],
             ]);

        $response = $this->get(route('orders.index'));

        $response->assertOk();

        $this->assertScopeCalled('unpaid', Order::class);
        $this->assertScopeCalled('createdAtDesc', Order::class);
    }
}

如果您想断言查询作用域被调用的次数,只需将数字作为assertScopeCalled()方法的第三个参数即可。

// The `unpaid` scope must have been called 2 times in tested code.
$this->assertScopeCalled('unpaid', Order::class, 2);

变更日志

请参阅CHANGELOG了解最近更改的更多信息。

贡献

请参阅CONTRIBUTING了解详细信息。

安全

如果您发现任何与安全相关的问题,请通过tkaratug@hotmail.com.tr发送电子邮件,而不是使用问题跟踪器。

致谢

许可证

MIT许可证(MIT)。请参阅许可证文件了解更多信息。