You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am currently refactoring my old models factories to finish migration from Laravel 7 to Laravel 8 and encountered with the minor problem related to the new factories states logic.
My automated tests often contain PHPUnit Data Providers with the arrays of states needed to be applied to the models I testing. L7 way to apply multiple states was quite easy to do that via states() method, but L8 does not provide such a method anymore 😕
Instead of full rewriting those tests where Data Providers have models states, I decided to write a trait enabling old L7 states() logic at newly refactored factories and supporting callbacks to use new L8 states methods with parameters:
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Arr;
trait FactoryApplyStates
{
/**
* Applies one or more states to a model factory
*
* @param string|array $stateMethods
* @return Factory
* @throws \Exception
*/
public function applyStates($stateMethods = null)
{
$stateMethods = Arr::wrap($stateMethods);
$factory = $this;
/* @var Factory $factory */
foreach ($stateMethods as $stateMethod) {
if (is_callable($stateMethod)) {
$factory = $stateMethod($factory);
} else {
if (!is_string($stateMethod)) {
throw new \Exception('Incorrect state name: must be a name of method');
}
if (!method_exists($this, $stateMethod)) {
throw new \Exception('Unsupported state for ' . __CLASS__ . ': ' . $stateMethod . '() method does not exist');
}
$factory = $factory->{$stateMethod}();
}
}
return $factory;
}
}
Now with this trait I can use Data Provider like this (assuming ArticleFactory has states active(), hidden(), suspended(), and with_images($imagesNumber = 1))
public function articleStatesDataProvider()
{
return [
'active article with images' => [
'states' => [
'active',
'with_images', // state will use default number of images
],
],
'hidden article with images' => [
'states' => [
'hidden',
function (ArticleFactory $factory) {
return $factory->with_images(4); // callback allows to pass specific parameters to a factory state
},
],
],
'suspended article' => [
'states' => 'suspended', // single state also can be passed as a string with state name
],
];
}
/**
* @dataProvider articleStatesDataProvider
*/
public function testAdminCanSeeAllArticles($states)
{
$article= Article::factory()
->applyStates($states)
->create();
...
}
I'm not sure if I personally use those multiple states not the common way other people usually do. And don't know if I'll use states with parameters at dataProviders frequently in the nearest future (thus bringing that callbacks' relative complexity into dataProviders), but at least this allows me not to completely rewrite my tests to use new Laravel 8 models factories.
How do you think, is it worth to have such a method at Laravel 8 Factory out of the box or my situation with tests is too specific?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Hello
I am currently refactoring my old models factories to finish migration from Laravel 7 to Laravel 8 and encountered with the minor problem related to the new factories states logic.
My automated tests often contain PHPUnit Data Providers with the arrays of states needed to be applied to the models I testing. L7 way to apply multiple states was quite easy to do that via states() method, but L8 does not provide such a method anymore 😕
Instead of full rewriting those tests where Data Providers have models states, I decided to write a trait enabling old L7 states() logic at newly refactored factories and supporting callbacks to use new L8 states methods with parameters:
Now with this trait I can use Data Provider like this (assuming ArticleFactory has states active(), hidden(), suspended(), and with_images($imagesNumber = 1))
I'm not sure if I personally use those multiple states not the common way other people usually do. And don't know if I'll use states with parameters at dataProviders frequently in the nearest future (thus bringing that callbacks' relative complexity into dataProviders), but at least this allows me not to completely rewrite my tests to use new Laravel 8 models factories.
How do you think, is it worth to have such a method at Laravel 8 Factory out of the box or my situation with tests is too specific?
Beta Was this translation helpful? Give feedback.
All reactions