php 如何将函数从闭包移动到普通函数

zpqajqem  于 2023-04-19  发布在  PHP
关注(0)|答案(3)|浏览(112)

我在试着让害虫测试文件更容易阅读。
目前,我有一些标准测试:

test('can get subscribers latest subscription', function () {
     $this->seed(PlansTestSeeder::class);
    $this->seed(SubscriptionsTestSeeder::class);

    $this->assertDatabaseCount('plans', 2);
    $this->assertDatabaseCount('subscriptions', 0);

    Subscription::factory()->create([
        "plan_id" => Plan::where("slug", "bronze")->first()->id
    ]);
    Subscription::factory()->create([
        "plan_id" => Plan::where("slug", "silver")->first()->id
    ]);
    Subscription::factory()->create([
        "plan_id" => Plan::where("slug", "silver")->first()->id,
        "status"  => "expired"
    ]);
    Subscription::factory()->trashed()->create();

    $this->assertDatabaseCount('subscriptions', 4);

});

test('can get subscribers active subscriptions', function () {
    $this->seed(PlansTestSeeder::class);
    $this->seed(SubscriptionsTestSeeder::class);

    $silverPlan = Plan::where("slug", "silver")->first();

    $subscription1 = Subscription::factory()->create([
        "plan_id"         => Plan::where("slug", "silver")->first()->id,
        "subscriber_id"   => 1,
        "subscriber_type" => "ApresourcingFramework\Billing\Tests\Models\Subscriber",
        "created_at"      => now()->subDays(2),
        "started_at"      => now()->subDays(2)
    ]);
    $subscription2 = Subscription::factory()->create([
        "plan_id"         => $silverPlan->id,
        "subscriber_id"   => 1,
        "subscriber_type" => "ApresourcingFramework\Billing\Tests\Models\Subscriber",
        "created_at"      => now()->subDays(1),
        "started_at"      => now()->subDays(1)
    ]);

    $user         = Subscriber::find(1);
    $subscription = $user->latestSubscription();
    expect($subscription->id)->toBe($subscription2->id);
});

但是为了提醒自己我写了什么测试,我必须一遍又一遍地上下滚动页面。
我想做的是更改为以下内容:

test('can get subscribers latest subscription', getLatestSubscription());
test('can get subscribers active subscriptions', getActiveSubscriptions());

function getLatestSubscription() {
    /// function code here
});

function getActiveSubscriptions() {
    // function code here
});

然而,测试函数包含对$this的引用,它在普通闭包中可用,但在标准函数中不可用,因为我在这里设置了它。
编辑:我正在使用laravel pest插件-我不确定这是否会对$this的使用产生影响
有什么办法可以绕过这个吗?

lf5gs5x2

lf5gs5x21#

感谢repliers中的一些提示,虽然没有我希望的那么整洁,但至少这意味着所有的test('description of test')调用都在php文件底部的一个地方。

$createSubscription = function () {

    $this->seed(PlansTestSeeder::class);
    $this->seed(SubscriptionsTestSeeder::class);

    $this->assertDatabaseCount('plans', 2);
    $this->assertDatabaseCount('subscriptions', 0);

    Subscription::factory()->create([
        "plan_id" => Plan::where("slug", "bronze")->first()->id
    ]);
    Subscription::factory()->create([
        "plan_id" => Plan::where("slug", "silver")->first()->id
    ]);
    Subscription::factory()->create([
        "plan_id" => Plan::where("slug", "silver")->first()->id,
        "status"  => "expired"
    ]);
    Subscription::factory()->trashed()->create();

    $this->assertDatabaseCount('subscriptions', 4);

};

$createBronzeSubscription = function () {
    $this->seed(PlansTestSeeder::class);
    $this->seed(SubscriptionsTestSeeder::class);

    Subscription::factory()->create([
        "plan_id" => Plan::where("slug", "bronze")->first()->id
    ]);

    $this->assertDatabaseCount('subscriptions', 1);
};

test('can create subscription', function () use ($createSubscription) {
    return \Closure::bind(\Closure::fromCallable($createSubscription), $this, get_class($this))($this);
});

test('can create bronze subscription', function () use ($createBronzeSubscription) {
    return \Closure::bind(\Closure::fromCallable($createBronzeSubscription), $this, get_class($this))($this);
});
vhmi4jdf

vhmi4jdf2#

练习

考虑一下这个,它修改了你的分支函数,使每个函数都返回一个匿名函数,并满足了你希望看到的调用位置:

function getLatestSubscription()
{
    return function () {
        // function code here
    };  
};

function getActiveSubscriptions()
{
    return function () {
        // function code here
    };  
};

test('can get subscribers latest subscription', getLatestSubscription());
test('can get subscribers active subscriptions', getActiveSubscriptions());

如果你对在同一作用域中将函数作为闭包变量感到满意,你可以通过以下方式删除一个级别的函数调用:

$getLatestSubscription = function () {
    // function code here
};

$getActiveSubscriptions = function () {
    // function code here
};

test('can get subscribers latest subscription', $getLatestSubscription);
test('can get subscribers active subscriptions', $getActiveSubscriptions);

理论

由于Pest test函数接受Closure作为其第二个参数,并在内部将该闭包绑定到测试用例,因此以下任何行为都是相同的:

test('closure literal', function () {
    $this->helperMethod();
    expect(true)->toBeTrue();
});
$closureVariable = function () {
    $this->helperMethod();
    expect(true)->toBeTrue();
};
test('closure variable', $closureVariable);
function closureFactory()
{
    return function () {
        $this->helperMethod();
        expect(true)->toBeTrue();
    };  
}
test('closure factory', closureFactory());

对于您的用例来说,最后一种方法可能有些多余,但是在您的测试用例在几个方面有所不同的情况下可能会很有用。

t2a7ltrp

t2a7ltrp3#

方法1:从闭包内部调用函数:

function getActiveSubscriptions($obj) {
  // use $obj instead of $this
  $obj->doSomething();
}

test('can get subscribers latest subscription', 
   function () { 
        getLatestSubscription($this); 
   }
);

方法2:重写test函数,使其接受函数名而不是闭包。例如:

function test($text, $fun) {
    print $text;
    print $fun();
  }

  function getLatestSubscription() {
    return "123";
  }

  test('can get subscribers latest subscription', 'getLatestSubscription');

相关问题