Ala*_*bak 5 php phpunit laravel laravel-5.3
我正在尝试使用模型工厂在数据提供程序中创建模型。如果我在设置方法中或直接在测试中使用工厂,则可以使用,但是如果我尝试在数据提供程序中使用它,则会出现错误:
1)警告
为MyClassTest :: testSomeMethod指定的数据提供者无效。
无法找到名称为[default] [App \ Model \ User]的工厂。
工厂定义:
/** @var \Illuminate\Database\Eloquent\Factory $factory */
$factory->define(\App\Model\User::class, function (Faker\Generator $faker) {
static $password;
return [
'id' => $faker->unique()->numberBetween(1, 10000),
'email_address' => $faker->unique()->safeEmail,
'remember_token' => str_random(10),
'password' => $password ?: $password = bcrypt('secret'),
];
});
$factory->state(\App\Model\User::class, 'guest', function ($faker) {
return [
'role_id' => 9999,
];
});
Run Code Online (Sandbox Code Playgroud)
我给工厂打电话:
factory(\App\Model\User::class)->states('guest')->make();
Run Code Online (Sandbox Code Playgroud)
是Laravel的错误,还是我在这里错过了一些东西?
编辑:
经过一些调试之后,我发现工厂定义没有在数据提供者调用之前加载,而是在调用setUp()方法时(即在数据提供者调用之后发生)调用了(即定义了)工厂定义,因此找不到工厂在数据提供者中。
因此在我看来,不可能在数据提供程序中使用工厂(或测试类中的任何静态方法)。否则我应该做一些事情来在我的数据提供者方法中定义工厂!
我在另一个问题(由同一问题引起)中找到了答案
因此,可以根据此答案通过调用$this->createApplication();或$this->refreshApplication();在数据提供者方法中解决此问题,或根据此答案在构造函数中调用它来解决此问题
该代码将如下所示
public function dataProvider() {
$this->refreshApplication(); // or $this->createApplication();
$user = factory(\App\Model\User::class)->states('guest')->make();
// ...
// another code to generate data ....
// ...
return $someFakeData;
}
Run Code Online (Sandbox Code Playgroud)
我尝试过并工作了,尽管我觉得这是一种解决方法,而不是事情应该如何工作,但任何“更清洁”的建议都会受到赞赏。
可以在您的数据提供程序中使用工厂,并且仍然可以使用数据库事务!
今天这让我很沮丧,我找到了一个受这个答案启发的解决方案,我找到了这个答案
它不漂亮,但它是:
更新我也把它变成了一篇博客文章,它更详细一点:https : //technicallyfletch.com/how-to-use-laravel-factories-inside-a-data-provider/
首先,我修改了使用提供程序的方式。我期望一个函数,我可以从中解构参数,而不是像往常一样期待参数列表。这就是将工厂的执行推迟到我进入我的测试用例之后的原因。
/**
* @test
* @dataProvider validationProvider
*/
public function it_validates_payload($getData)
{
// data provider now returns a function which we can invoke to
// destructure our arguments here.
[$ruleName, $payload] = $getData();
$this->post(route('participants.store'), $payload)
->assertSessionHasErrors($ruleName);
}
Run Code Online (Sandbox Code Playgroud)
我的提供者现在变成了这样:
public function validationProvider()
{
return [
'it fails if participant_type_id does not exist' => [
function () {
return [
'participant_type_id',
array_merge($this->getValidData(), ['participant_type_id' => null])
];
}
],
'it fails if first_name does not exist' => [
function () {
return [
'first_name',
array_merge($this->getValidData(), ['first_name' => null])
];
}
],
'it fails if last_name does not exist' => [
function () {
return [
'last_name',
array_merge($this->getValidData(), ['last_name' => null])
];
}
],
'it fails if email is not unique' => [
function () {
$existingEmail = factory(Participant::class)->create([
'email' => 'pbeasly@dundermifflin.com'
])->email;
return [
'email',
array_merge($this->getValidData(), ['email' => $existingEmail])
];
}
],
];
}
Run Code Online (Sandbox Code Playgroud)
然后这有点离题,但它很好地说明了你可以推迟工厂。该getValidData()方法仅返回一组有效数据,因此每个测试一次仅断言一个验证错误。它也使用工厂:
private function getValidData()
{
return [
'practice_id' => factory(Practice::class)->create()->id,
'participant_type_id' => 1,
'first_name' => 'John',
'last_name' => 'Doe',
];
}
Run Code Online (Sandbox Code Playgroud)
有些事情仍然困扰着我
id被供应商的第一次执行后创建的,你可以拉从国家的ID,而不是使该数据库每次新的呼叫。否则,当您需要它时,它是一个有效的解决方案,我希望它可以帮助其他人,如果他们碰巧找到了这个!
| 归档时间: |
|
| 查看次数: |
1307 次 |
| 最近记录: |