Php 从traits内部的类访问属性
我试图使用mock为Php 从traits内部的类访问属性,php,laravel,phpunit,traits,mockery,Php,Laravel,Phpunit,Traits,Mockery,我试图使用mock为startedAt()方法编写一个单元测试,但是我面临的问题是,我认为我无法从startedAt()方法内部访问生成器实例 为了测试startedAt()方法,我创建了一个名为ExampleFilters的fixture类,并让它扩展Filters的父类。在ExampleFiltersclass I的内部,导入FiltersByStartDatetrait 有人对我如何从FiltersByStartDatetrait访问builder属性有什么建议吗 有什么想法吗 <?
startedAt()
方法编写一个单元测试,但是我面临的问题是,我认为我无法从startedAt()方法内部访问生成器实例
为了测试startedAt()
方法,我创建了一个名为ExampleFilters
的fixture类,并让它扩展Filters
的父类。在ExampleFilters
class I的内部,导入FiltersByStartDate
trait
有人对我如何从FiltersByStartDate
trait访问builder
属性有什么建议吗
有什么想法吗
<?php
namespace App\Filters\Concerns;
trait FiltersByStartDate
{
/**
* Filter a query to include models of a specific date started.
*
* @param array $startedAt
* @return \Illuminate\Database\Eloquent\Builder
*/
public function startedAt($startedAt)
{
if (isset($startedAt[1])) {
$this->builder->whereHas('currentEmployment', function ($query) use ($startedAt) {
$query->whereBetween('started_at', [
$startedAt[0],
$startedAt[1]
]);
});
} else {
$this->builder->whereHas('currentEmployment', function ($query) use ($startedAt) {
$query->whereDate('started_at', $startedAt[0]);
});
}
return $this->builder;
}
}
我觉得你用错了特质<代码>特性旨在通过使开发人员能够在不同类层次结构中的几个独立类中自由重用方法集来减少单个继承的某些限制。
一般来说,特性不应使用仅存在于使用该特性的类中的属性。如果trait需要一个属性来工作,那么该属性应该是trait的属性,而不是使用trait的类的属性。创建依赖于using类的属性的trait会增加复杂性和对该类或扩展类的依赖性该trait的原因是我有6个XXXFilters类,它们都使用相同的startedAt方法,所以我想创建一个trait并将其包含在内。如何从FiltersByStartDate访问builder属性特质?
,你不能。FiltersByStartDate没有builder
属性。不过,您可以访问ExampleFilters
的“builder”属性<代码>(新示例过滤器($request))->builder
问题就在这里。我不能硬编码ExampleFilters,因为如果这个特性被6个不同的类使用,那么这就是一个问题。也许你应该向我们展示你正在尝试编写的测试,它要求你从FiltersByStartDate特性访问生成器属性,也许有一种不同的方法,实际上并不需要它。或者,您可以将builder
属性添加到trait本身,然后您可以在测试中自由地模拟该属性/getter,以设置您需要的任何内容
<?php
namespace Tests\Fixtures;
use App\Filters\Concerns\FiltersByStartDate;
use App\Filters\Filters;
class ExampleFilters extends Filters
{
use FiltersByStartDate;
}
<?php
namespace App\Filters;
use Illuminate\Http\Request;
abstract class Filters
{
/**
* @var \Illuminate\Http\Request
*/
protected $request;
/**
* The Eloquent builder.
*
* @var \Illuminate\Database\Eloquent\Builder
*/
protected $builder;
/**
* Registered filters to operate upon
*
* @var array
*/
protected $filters = [];
/**
* Create a new class instance.
*
* @param \Illuminate\Http\Request $request
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Apply the filters.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return \Illuminate\Database\Eloquent\Builder
*/
public function apply($builder)
{
$this->builder = $builder;
foreach ($this->getFilters() as $filter => $value) {
if (method_exists($this, $filter)) {
$this->$filter($value);
}
}
return $this->builder;
}
/**
* Fetch all relevant filters from the request.
*
* @return array
*/
public function getFilters()
{
return array_filter($this->request->only($this->filters));
}
}
<?php
namespace Tests\Unit\Filters\Concerns;
use Illuminate\Database\Query\Builder;
use Tests\Fixtures\ExampleFilters;
use Tests\TestCase;
/*
* @group filters
*/
class FiltersByStartDateTest extends TestCase
{
/* @var Tests\Fixtures\ExampleFilters */
protected $subject;
public function setUp(): void
{
$this->subject = app(ExampleFilters::class);
}
/** @test */
public function models_can_be_filtered_by_their_start_date()
{
// $this->markTestIncomplete();
$dateSet = ['2020-01-01 00:00:00'];
$mock = \Mockery::mock(Builder::class)
->shouldReceive('whereHas', \Mockery::any())
->shouldReceive('whereDate')
->withArgs(['started_at', $dateSet])
->once()
->andReturn(true)
->getMock();
dd($this->subject->startedAt($dateSet));
$builderMockFromDate = $this->subject->startedAt($dateSet);
$this->assertSame($builderMockFromDate, $mock);
}
}