铸造
编辑本页铸造
铸造支持教义/ orm
(与教义/ doctrine-bundle),教义/ mongodb-odm
(与教义/ mongodb-odm-bundle)或两者的结合。
安装
1
$作曲家需要zenstruck/foundry—dev
使用: *
这个bundle中的命令,请确保ob娱乐下载Symfony MakerBundle安装。
如果不使用Symfony ob娱乐下载Flex,请确保在您的测验/dev环境。
与这些文档中使用的实体相同
对于文档的其余部分,将使用以下示例实体:欧宝官网下载app
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
名称空间应用程序\实体;使用学说\ORM\映射作为ORM;/ * * *@ORM实体(repositoryClass = \ App \ Repository \ CategoryRepository) * /类类别{/ * * *@ORM* \ Id ()@ORM* \ GeneratedValue ()@ORM\列(类型=“整数”)* /私人$id;/ * * *@ORM\Column(type="string", length=255) */私人$的名字;公共函数__construct(字符串$的名字){$这->name =$的名字;}/ /……getter / setter}
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
名称空间应用程序\实体;使用学说\ORM\映射作为ORM;/ * * *@ORM实体(repositoryClass = \ App \ Repository \ PostRepository) * /类帖子{/ * * *@ORM* \ Id ()@ORM* \ GeneratedValue ()@ORM\列(类型=“整数”)* /私人$id;/ * * *@ORM\Column(type="string", length=255) */私人$标题;/ * * *@ORM\Column(type="text", nullable=true) */私人$身体;/ * * *@ORM\列(type = " datetime) * /私人$createdAt;/ * * *@ORM\Column(type="datetime", nullable=true) */私人$publishedAt;/ * * *@ORM\ ManyToOne (targetEntity =类别::类)*@ORM\ JoinColumn * /私人$类别;公共函数__construct(字符串$标题){$这->title =$标题;$这->createdAt =新\ DateTime (“现在”);}/ /……getter / setter}
模型的工厂
使用Foundry最好的方法是生成一个工厂每个实体的类。您可以跳过此步骤并使用匿名的工厂,但模型的工厂给你IDE自动完成和访问其他有用的功能。
生成
使用maker命令为你的一个实体创建一个模型工厂:
1 2 3 4 5 6 7 8
$bin/console make:factory >创建工厂的实体类为下一步:打开你的新工厂和集默认值/状态。
该命令将生成一个PostFactory
类,看起来像这样:
12 34 56 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/ / src /工厂/ PostFactory.php名称空间应用程序\工厂;使用应用程序\实体\帖子;使用应用程序\存储库\PostRepository;使用Zenstruck\铸造\RepositoryProxy;使用Zenstruck\铸造\ModelFactory;使用Zenstruck\铸造\代理;/ * * *@extendsModelFactory * *@methodstatic Post|代理createOne(数组$attributes = []) *@methodstatic Post[]|Proxy[] createMany(int $number, array|callable $attributes = []) *@methodstatic Post[]&Proxy[] createSequence(数组|可调用$sequence) *@method静态后|代理查找(对象|数组|混合$criteria) *@methodstatic Post|代理findOrCreate(数组$attributes) *@method静态|代理优先(字符串$sortedField = 'id') *@method静态|代理最后(字符串$sortedField = 'id') *@method静态发布|代理随机(数组$attributes = []) *@methodstatic Post|代理randomOrCreate(array $attributes = [])) *@methodstatic Post[]|Proxy[] all() * .使用实例@methodstatic Post[]|Proxy[] findBy(array $attributes) *@methodstatic Post[]|Proxy[] randomSet(int $number, array $attributes = [])) *@methodstatic Post[]|Proxy[] randomRange(int $min, int $max, array $attributes = [])) *@method静态PostRepository|RepositoryProxy repository() *@method发布|代理创建(数组|可调用的$attributes = []) */ 最后类PostFactory扩展ModelFactory{/ * * *@seehttps://github.com/zenstruck/foundry#factories-as-services * *@todo如果需要注入服务*/公共函数__construct(){父::__construct ();}/ * * *@seehttps://github.com/zenstruck/foundry#model-factories * *@todo在这里添加默认值*/受保护的函数getDefaults():数组{返回[];}/ * * *@seehttps://github.com/zenstruck/foundry初始化* /受保护的函数初始化():自我{返回$这// ->afterInstantiate(function(Post $ Post) {});}受保护的静态函数getClass():字符串{返回帖子::类;}}
提示
使用:工厂——测试
会生成工厂在测试/工厂
.
请注意
生成的@method
上面的文档块可以在PhpStorm中自动完成,但在PHPStan中会导致错误。要为您的工厂支持PHPStan,您需要也添加如下的dockblock:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/** *…* *@phpstan-method Proxy create(array|callable $attributes = []) *@phpstan-method static Proxy createOne(array $attributes = []) *@phpstan-method static Proxy find(对象|数组|mixed $criteria) *@phpstan-method static Proxy findOrCreate(array $attributes) *@phpstan-method static Proxy first(string $sortedField = 'id') *@phpstan-method static Proxy last(string $sortedField = 'id') *@phpstan-method static Proxy random(array $attributes = []) *@phpstan-method static Proxy randomOrCreate(array $attributes = []) *@phpstan-method静态列表> all() *@phpstan-method static list> createMany(int $number, array|callable $attributes = []) * .@phpstan-method static list> createSequence(数组|可调用$sequence) *@phpstan-method static list> findBy(array $attributes) *@phpstan-method static list> randomRange(int $min, int $max, array $attributes = []) *@phpstan-method static list> randomSet(int $number, array $attributes = []) *@phpstan-method static RepositoryProxy repository() */ 最后类PostFactory扩展ModelFactory{/ /……}
在getDefaults ()
,您可以返回任何新对象应该具有的所有默认值的数组。骗子可轻松获取随机数据:
1 2 3 4 5 6 7 8 9
受保护的函数getDefaults():数组{返回[// ob娱乐下载Symfony的属性访问组件用于填充属性//这意味着setTitle()将被调用,或者你可以有一个$title构造函数参数“标题”= >自我::骗子()->独特的()->句子(),“身体”= >自我::骗子()->句子()];}
提示
最好有getDefaults ()
返回用于持久化有效对象的属性(所有非空字段)。
提示
使用:工厂——所有字段
将为实体的所有字段生成默认值,而不仅仅是非空字段。
使用你的工厂
12 34 56 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
使用应用程序\工厂\PostFactory;//创建/保存从getDefaults()中获取的随机数据PostFactory::createOne ();//或为某些属性提供值(其他属性将是随机的)PostFactory::createOne ([“标题”= >“我的名字”]);// createOne()返回封装在Proxy对象中的持久Post对象$帖子= PostFactory::createOne ();// "Proxy"神奇地调用底层的Post方法,并被类型提示为"Post"$标题=$帖子->getTitle ();// getTitle()可以由IDE自动完成!//如果你需要Post对象,使用->object()$realPost=$帖子->对象();//从getDefaults()中创建5个随机数据PostFactory::createMany (5);//返回Post[]|Proxy[]PostFactory::createMany (5, (“标题”= >“我的名字”]);//创建5个递增标题的帖子PostFactory::createMany (5,静态函数(int$我){返回[“标题”= >“标题我美元”];// "Title 1", "Title 2",…“标题5”});//为给定的属性找到一个持久化对象,如果没有找到,用属性创建PostFactory::findOrCreate ([“标题”= >“我的名字”]);//返回Post|ProxyPostFactory::第();//获取第一个对象(假设一个自动递增的"id"列)PostFactory::第一次(“createdAt”);//假设"createdAt"是一个datetime列,它将返回最新的对象PostFactory::最后();//获取最后一个对象(假设一个自动递增的"id"列)PostFactory::最后一个(“createdAt”);//假设"createdAt"是一个datetime列,将返回最古老的对象PostFactory::截断();//清空数据库表PostFactory::count ();//持久化post的数量PostFactory::所有();// Post[]|Proxy[]所有持久化的PostPostFactory::findBy ([“作者”= >“凯文”]);// Post[]|匹配过滤器的Proxy[$帖子= PostFactory::找到(5);//发布id为5的|代理$帖子= PostFactory::找到([“标题”= >“我的第一篇文章”]);// Post|匹配过滤器的代理//获取一个随机的持久化对象$帖子= PostFactory::随机();//返回Post|Proxy$帖子= PostFactory::随机([“作者”= >“凯文”]);//通过传入的属性进行筛选//或自动持久化一个新的随机对象(如果不存在)$帖子= PostFactory::randomOrCreate ();$帖子= PostFactory::randomOrCreate ([“作者”= >“凯文”]);//过滤或创建传递的属性//获取一个被持久化的随机对象集$的帖子= PostFactory::randomSet (4);//包含4个Post|Proxy对象的数组$的帖子= PostFactory::randomSet (4, (“作者”= >“凯文”]);//通过传入的属性进行筛选//持久化对象的随机范围$的帖子= PostFactory::randomRange (0,5);//包含0-5个Post|Proxy对象的数组$的帖子= PostFactory::randomRange (0,5, (“作者”= >“凯文”]);//通过传入的属性进行筛选
可重用模型工厂“状态”
你可以在你的模型工厂中添加任何你想要的方法(即以某种方式创建对象的静态方法),但你也可以添加州:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
名称空间应用程序\工厂;使用应用程序\实体\帖子;使用Zenstruck\铸造\ModelFactory;最后类PostFactory扩展ModelFactory{/ /……公共函数发表():自我{//调用setPublishedAt()并传递一个随机的DateTime返回$这->addState ([“published_at”= >自我::骗子()->dateTime ()));}公共函数未发表的():自我{返回$这->addState ([“published_at”= >零]);}公共函数withViewCount(int$数= null):自我{返回$这->addState (函数()使用($数){返回[“view_count”= >$数??自我::骗子()->numberBetween (0,10000));});}}
您可以使用状态使您的测试非常显式,以提高可读性:
12 3 4 5 6 7 8 9 10 11 12 13 14 15
//从不使用构造函数"new PostFactory()"),但是使用// "new()"方法定义状态后,调用“create()”来创建//持久化模型。$帖子= PostFactory::新()->未发表的()->create ();$帖子= PostFactory::新()->withViewCount (3.)->create ();//组合多个状态$帖子= PostFactory::新()->未发表的()->withViewCount (10)->create ();//不需要参数的状态可以作为字符串添加到PostFactory::new()$帖子= PostFactory::新(“发布”,“withViewCount”)->create ();
属性
用于实例化对象的属性可以通过几种方式添加。属性可以是数组,或可调用的返回一个数组。使用一个可调用的确保在实例化期间为每个对象分别运行可调用对象时的随机数据。
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
使用应用程序\实体\类别;使用应用程序\实体\帖子;使用应用程序\工厂\CategoryFactory;使用应用程序\工厂\PostFactory;使用函数Zenstruck\铸造\骗子;// "new()"的第一个参数允许你覆盖默认值//在PostFactory::getDefaults()中定义的值$的帖子= PostFactory::新([“标题”= >“发布”])->withAttributes ([“身体”= >“帖子的身体…”,// CategoryFactory将用于为每个Post创建一个新的Category“类别”= > CategoryFactory::新([“名字”= >“php”))))->withAttributes ([//代理自动转换为它们的包装对象“类别”= > CategoryFactory::createOne ())->withAttributes (函数(){返回[“createdAt”= >骗子()->dateTime ()];})//参见下面的faker部分//创建“2”Post->许多(2)->创建([“标题”= >“不同的标题”]);$的帖子[0]->getTitle ();// "不同的标题"$的帖子[0]->getBody ();// "Post Body…"$的帖子[0]->getCategory ();//随机分类$的帖子[0]->getPublishedAt ();// \DateTime('上周')$的帖子[0]->getCreatedAt ();// random \DateTime$的帖子[1]->getTitle ();// "不同的标题"$的帖子[1]->getBody ();// "Post Body…"$的帖子[1]->getCategory ();//随机类别(与上面不同)$的帖子[1]->getPublishedAt ();// \DateTime('上周')$的帖子[1]->getCreatedAt ();// random \DateTime(与上面不同)
请注意
属性传递给创建*
方法与通过设置的任何属性合并getDefaults ()
而且withAttributes ()
.
序列
序列有助于在一次调用中创建不同的对象:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
使用应用程序\工厂\PostFactory;//根据属性序列创建/持久化2个postPostFactory::createSequence([[“名字”= >“标题1”]、[“名字”= >“标题2”],]);//使用增量索引的序列回调创建10个postPostFactory::createSequence (函数(){foreach(范围(1,10)作为$我) {收益率[“名字”= >“标题我美元”];}});// sequence也可以用于带有状态的工厂$的帖子= PostFactory::新()->未发表的()->序列([[“名字”= >“标题1”]、[“名字”= >“标题2”],])->create ();
骗子
此库为FakerPHP帮助您的工厂生成随机数据:
1 2 3 4 5 6 7
使用Zenstruck\铸造\工厂;使用函数Zenstruck\铸造\骗子;工厂::骗子()->名称();//随机名称//或者,使用helper函数骗子()->电子邮件();//随机邮件
请注意
1 2 3 4 5 6
#配置/包/ zenstruck_foundry.yamlwhen@dev:关于在测试环境中共享这个,请参阅Bundle配置部分zenstruck_foundry:骗子:地区:fr_FR#设置区域种子:5678#设置随机数生成器种子
请注意
要完全控制,您可以注册自己的摊贩\发电机
服务:
1 2 3 4 5
#配置/包/ zenstruck_foundry.yamlwhen@dev:关于在测试环境中共享这个,请参阅Bundle配置部分zenstruck_foundry:骗子:服务:my_faker# Faker\Generator实例的服务id
事件/钩子
以下事件可以添加到工厂。可以添加多个事件回调,它们将按照添加的顺序运行。
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
使用应用程序\工厂\PostFactory;使用Zenstruck\铸造\代理;PostFactory::新()->beforeInstantiate (函数(数组$属性):数组{// $attributes将用于实例化对象,根据需要进行操作$属性[“标题”] =“不同的标题”;返回$属性;//必须返回最终的$属性})->afterInstantiate (函数(文章$对象数组,$属性):无效{// $object是实例化的对象// $attributes包含用于实例化对象和任何附加项的属性})->afterPersist (函数(代理$代理数组,$属性){/*@var发布$proxy *///该事件只在对象被持久化时调用// $proxy是包装持久化对象的代理// $attributes包含用于实例化对象和任何附加项的属性})//如果第一个参数被类型提示为对象,它将被传递给闭包(而不是代理)->afterPersist (函数(文章$对象数组,$属性){//该事件只在对象被持久化时调用// $object是持久的Post对象// $attributes包含用于实例化对象和任何附加项的属性})//允许多个事件->beforeInstantiate (函数($属性){返回$属性;})->afterInstantiate (函数(){})->afterPersist (函数(){});
你也可以直接在你的模型工厂类中添加钩子:
1 2 3 4 5 6
受保护的函数初始化():自我{返回$这->afterPersist (函数(){});}
读初始化了解更多关于初始化()
方法。
初始化
您可以覆盖您的模型工厂初始化()
方法添加默认状态/逻辑:
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
名称空间应用程序\工厂;使用应用程序\实体\帖子;使用Zenstruck\铸造\ModelFactory;最后类PostFactory扩展ModelFactory{/ /……受保护的函数初始化():自我{返回$这->(出版)//默认发布->instantiateWith (函数(数组$属性){返回新Post ();//该工厂的自定义实例化})->afterPersist (函数(){})//此工厂的默认事件;}}
请注意
确保链的状态/钩子这个美元
因为工厂不可变的.
实例化
默认情况下,通过使用对象的构造函数,以正常的方式实例化对象。使用与构造函数参数匹配的属性。其余属性使用Symfony的属性设置为对象ob娱乐下载PropertyAccess组件(setters/public属性)。任何额外的属性都会引发异常。
你可以通过以下几种方式定制实例化器:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
使用应用程序\实体\帖子;使用应用程序\工厂\PostFactory;使用Zenstruck\铸造\Instantiator;//设置当前工厂的实例化器PostFactory::新()//实例化对象而不调用构造函数->instantiateWith ((新Instantiator ())->withoutConstructor ())//实例化时忽略"foo"和"bar"属性->instantiateWith ((新Instantiator ())->allowExtraAttributes ([“foo”,“酒吧”)))//实例化时忽略所有额外的属性->instantiateWith ((新Instantiator ())->allowExtraAttributes ())//实例化时强制设置title和body->instantiateWith ((新Instantiator ())->alwaysForceProperties ([“标题”,“身体”)))//从不使用setter,总是“强制设置”属性(即使是private/protected,也不使用setter)->instantiateWith ((新Instantiator ())->alwaysForceProperties ())//可以组合不同的“模式”->instantiateWith ((新Instantiator ())->withoutConstructor ()->allowExtraAttributes ()->alwaysForceProperties ())//实例化器只是一个可调用对象,你可以提供自己的实例化器->instantiateWith (函数(数组$属性、字符串$类):对象{返回新Post ();/ /……你自己的逻辑});
你可以为你所有的工厂定制实例化器(仍然可以被工厂实例化器覆盖):
1 2 3 4 5 6 7 8 9
#配置/包/ zenstruck_foundry.yamlwhen@dev:关于在测试环境中共享这个,请参阅Bundle配置部分zenstruck_foundry:instantiator:without_constructor:真正的#总是实例化对象而不调用构造函数allow_extra_attributes:真正的#总是忽略额外的属性always_force_properties:真正的#总是“强制设置”属性#或服务:my_instantiator#你自己的可调用服务的完全控制
不可变的
工厂是不可变的:
1 2 3 4 5 6 7 8
使用应用程序\工厂\PostFactory;$工厂= PostFactory::新();$factory1=$工厂->withAttributes ([]);返回一个新的PostFactory对象$factory2=$工厂->instantiateWith (函数(){});返回一个新的PostFactory对象$factory3=$工厂->beforeInstantiate (函数(){});返回一个新的PostFactory对象$factory4=$工厂->afterInstantiate (函数(){});返回一个新的PostFactory对象$factory5=$工厂->afterPersist (函数(){});返回一个新的PostFactory对象
原则的关系
假设您的实体遵循原则关系的最佳实践你在用默认instantiator、铸造只是工作教义关系。不同的关系和实体的创建方式有一些细微差别。下面尝试为每种关系类型记录这些内容。
多对一
以下假设评论
实体具有多对一关系帖子
:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
使用应用程序\工厂\CommentFactory;使用应用程序\工厂\PostFactory;//示例1:预创建Post并附加到Comment$帖子= PostFactory::createOne ();//代理实例CommentFactory::createOne ([“职位”= >$帖子]);CommentFactory::createOne ([“职位”= >$帖子->对象()));//功能与上面相同//例2:预先创建post,然后随机选择一个PostFactory::createMany (5);//创建5个postCommentFactory::createOne ([“职位”= > PostFactory::随机()));//或创建许多,每个与不同的随机PostCommentFactory::createMany (5,//创建5个注释函数(){//注意回调-这确保了5个注释中的每一个都有不同的Post返回[“职位”= > PostFactory::随机()];//每个评论设置为数据库中已经存在的帖子中的随机帖子});//示例3:为每个Comment创建一个单独的PostCommentFactory::createMany (5, (//这个属性是PostFactory的一个实例,它是为每个创建的Comment单独创建的“职位”= > PostFactory::新()));//例4:用同一个Post创建多个CommentsCommentFactory::createMany (5, (“职位”= > PostFactory::createOne (),//注意这里的createOne()]);
提示
建议您定义的唯一关系ModelFactory: getDefaults ()
是非空的多对一。
提示
还建议您ModelFactory: getDefaults ()
返回一个工厂
而不是被创建的实体:
12 3 4 5 6 7 8 9 10 11 12
受保护的函数getDefaults():数组{返回[/ /推荐“职位”= > PostFactory::新(),“职位”= > PostFactory::新()->发表(),//不推荐-可能会导致额外的意外帖子“职位”= > PostFactory::createOne (),“职位”= > PostFactory::新()->(出版)->create ());}
一对多
以下假设帖子
实体具有一对多的关系评论
:
1 2 3 4 5 6 7 8 9 10 11
使用应用程序\工厂\CommentFactory;使用应用程序\工厂\PostFactory;//示例1:创建一个包含6条评论的帖子PostFactory::createOne ([“评论”= > CommentFactory::新()->许多(6)));//示例2:创建6个帖子,每个帖子有4个评论(总共24个评论)PostFactory::createMany (6, (“评论”= > CommentFactory::新()->许多(4)));//示例3:创建6个帖子,每个帖子有0到10个评论PostFactory::createMany (6, (“评论”= > CommentFactory::新()->许多(0,10)));
多对多
以下假设帖子
实体具有多对多关系标签
:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
使用应用程序\工厂\PostFactory;使用应用程序\工厂\TagFactory;//示例1:预创建标签并附加到Post$标签= TagFactory::createMany (3.);PostFactory::createOne ([“标签”= >$标签]);//例2:预创建标签并选择一个随机集TagFactory::createMany (10);PostFactory::新()->许多(5)//创建5个帖子->创建(函数(){//注意回调-这确保了5个帖子中的每一个都有一个不同的随机集返回[“标签”= > TagFactory::randomSet (2));//每个帖子使用数据库中已经存在的2个随机标签});//示例3:预创建标签并选择一个随机范围TagFactory::createMany (10);PostFactory::新()->许多(5)//创建5个帖子->创建(函数(){//注意回调-这确保了5个帖子中的每一个都有不同的随机范围返回[“标签”= > TagFactory::randomRange (0,5));//每个帖子使用0到5个从数据库中已经存在的随机标签});//示例4:创建3个post,每个post有3个唯一的TagsPostFactory::createMany (3., (“标签”= > TagFactory::新()->许多(3.)));//示例5:创建3个帖子,每个帖子都有0到3个不同的标签PostFactory::createMany (3., (“标签”= > TagFactory::新()->许多(0,3.)));
工厂即服务
如果您的工厂需要依赖关系,您可以将它们定义为服务。属性对密码进行编码,这是一个非常常见的用例UserPasswordHasherInterface
服务。
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
/ / src /工厂/ UserFactory.php名称空间应用程序\工厂;使用应用程序\实体\用户;使用ob娱乐下载\组件\PasswordHasher\切肉机\UserPasswordHasherInterface;使用Zenstruck\铸造\ModelFactory;最后类UserFactory扩展ModelFactory{私人$passwordHasher;公共函数__construct(UserPasswordHasherInterface$passwordHasher){父::__construct ();$这->passwordHasher =$passwordHasher;}受保护的函数getDefaults():数组{返回[“电子邮件”= >自我::骗子()->独特的()->safeEmail (),“密码”= >“1234”,);}受保护的函数初始化():自我{返回$这->afterInstantiate (函数(用户$用户){$用户->向setPassword ($这->passwordHasher->hashPassword ($用户,$用户->getPassword ()));});}受保护的静态函数getClass():字符串{返回用户::类;}}
如果使用标准的Symfony Flex应ob娱乐下载用,这将是自动连接/自动配置的。如果不是,则注册服务并标记foundry.factory
.
正常使用工厂:
1 2
UserFactory::createOne ([“密码”= >“mypass”])->getPassword ();// " mpass "编码UserFactory::createOne ()->getPassword ();// "1234"编码(因为"1234"被设置为默认密码)
请注意
工厂作为服务需要所提供的包。
请注意
如果使用:工厂——测试
,工厂将在测试/工厂
目录,在标准的Symfony Flex应用程序中没有自动连接/自动配置。你必须手动注册这些服务。ob娱乐下载
匿名的工厂
Foundry可以用来为你没有模型工厂的实体创建工厂:
12 34 56 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
使用应用程序\实体\帖子;使用Zenstruck\铸造\AnonymousFactory;使用函数Zenstruck\铸造\工厂;使用函数Zenstruck\铸造\创建;使用函数Zenstruck\铸造\create_many;$工厂= AnonymousFactory::新(文章::类);$工厂=工厂(职位::类);//替代以上//拥有与ModelFactory相同的API$工厂->创建([“字段”= >“价值”]);$工厂->许多(5)->创建([“字段”= >“价值”]);$工厂->instantiateWith (函数(){});$工厂->beforeInstantiate (函数(){});$工厂->afterInstantiate (函数(){});$工厂->afterPersist (函数(){});//为给定的属性找到一个持久化对象,如果没有找到,用属性创建$工厂->findOrCreate ([“标题”= >“我的名字”]);$工厂->第();//获取第一个对象(假设一个自动递增的"id"列)$工厂->第一次(“createdAt”);//假设"createdAt"是一个datetime列,它将返回最新的对象$工厂->最后();//获取最后一个对象(假设一个自动递增的"id"列)$工厂->最后一个(“createdAt”);//假设"createdAt"是一个datetime列,将返回最古老的对象$工厂->截断();//清空数据库表$工厂->count ();//持久化Post的数量$工厂->所有();// Post[]|Proxy[]所有持久化的Post$工厂->findBy ([“作者”= >“凯文”]);// Post[]|匹配过滤器的Proxy[$工厂->找到(5);//发布id为5的|代理$工厂->找到([“标题”= >“我的第一篇文章”]);// Post|匹配过滤器的代理//获取一个随机的持久化对象$工厂->随机();//返回Post|Proxy$工厂->随机([“作者”= >“凯文”]);//通过传入的属性进行筛选//或自动持久化一个新的随机对象(如果不存在)$工厂->randomOrCreate ();$工厂->randomOrCreate ([“作者”= >“凯文”]);//过滤或创建传递的属性//获取一个被持久化的随机对象集$工厂->randomSet (4);//包含4个Post|Proxy对象的数组$工厂->randomSet (4, (“作者”= >“凯文”]);//通过传入的属性进行筛选//持久化对象的随机范围$工厂->randomRange (0,5);//包含0-5个Post|Proxy对象的数组$工厂->randomRange (0,5, (“作者”= >“凯文”]);//通过传入的属性进行筛选//存储库代理包装PostRepository(参见下面的存储库代理部分)$工厂->存储库();//方便函数$实体=创建(职位::类,“字段”= >“价值”]);$实体= create_many(职位::类,5, (“字段”= >“价值”]);
延迟冲洗
当同时创建/持久化多个工厂时,可以在不保存到数据库的情况下实例化所有工厂,然后一次性刷新它们,从而提高性能。要做到这一点,将操作包装在工厂::delayFlush ()
回调函数:
1 2 3 4 5 6
使用Zenstruck\铸造\工厂;工厂::delayFlush (函数(){CategoryFactory::createMany (One hundred.);//实例化/持久化但不刷新TagFactory::createMany (200);//实例化/持久化但不刷新});//单次刷新
没有坚持
工厂也可以创建对象而不持久化它们。这对于只想测试实际对象行为的单元测试或创建非实体对象的单元测试非常有用。创建时,它们仍然被包装在代理
稍后可选地保存。
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
使用应用程序\工厂\PostFactory;使用应用程序\实体\帖子;使用Zenstruck\铸造\AnonymousFactory;使用函数Zenstruck\铸造\实例化;使用函数Zenstruck\铸造\instantiate_many;$帖子= PostFactory::新()->withoutPersisting ()->create ();//返回Post|Proxy$帖子->setTitle (“别的东西”);//用object做某事$帖子->save ();//持久化Post (save()是Proxy上的一个方法)$帖子= PostFactory::新()->withoutPersisting ()->create ()->对象();//实际Post对象$的帖子= PostFactory::新()->withoutPersisting ()->许多(5)->create ();//返回Post[]|Proxy[]//匿名工厂:$工厂=新AnonymousFactory (Post::类);$实体=$工厂->withoutPersisting ()->创建([“字段”= >“价值”]);//返回Post|Proxy$实体=$工厂->withoutPersisting ()->创建([“字段”= >“价值”])->对象();//实际Post对象$实体=$工厂->withoutPersisting ()->许多(5)->创建([“字段”= >“价值”]);//返回Post[]|Proxy[]//方便函数$实体=实例化(职位::类,“字段”= >“价值”]);$实体= instantiate_many(职位::类,5, (“字段”= >“价值”]);
如果您希望您的模型工厂在默认情况下不持久,请重写它初始化()
方法添加此行为:
1 2 3 4 5 6
受保护的函数初始化():自我{返回$这->withoutPersisting ();}
现在,在使用这个工厂创建对象之后,您必须调用- - - - - - >保存()
将它们持久化到数据库中。
提示
如果你想在默认情况下禁用所有模型工厂的持久化:
- 创建一个可扩展的抽象模型工厂
Zenstruck \铸造\ ModelFactory
. - 覆盖
初始化()
方法,如上所示。 - 让你所有的样板工厂都以此为基础。
使用DoctrineFixturesBundle
铸造厂开箱即用DoctrineFixturesBundle.你可以简单地在fixture文件中使用你的工厂和故事:
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/ / src / DataFixtures / AppFixtures.php名称空间应用程序\DataFixtures;使用应用程序\工厂\CategoryFactory;使用应用程序\工厂\CommentFactory;使用应用程序\工厂\PostFactory;使用应用程序\工厂\TagFactory;使用学说\包\FixturesBundle\夹具;使用学说\持久性\ObjectManager;类AppFixtures扩展夹具{公共函数负载(ObjectManager$经理){//创建10个类别CategoryFactory::createMany (10);//创建20个标签TagFactory::createMany (20.);//创建50个PostPostFactory::createMany (50,函数(){返回[//每个帖子都有一个随机的类别(从上面创建的类别中选择)“类别”= > CategoryFactory::随机(),//每个Post将有0到6个标签(从上面创建的标签中选择)“标签”= > TagFactory::randomRange (0,6),//每个Post将有0到10个新建的Comment“评论”= > CommentFactory::新()->许多(0,10),);});}}
运行原则:设备:负载
正常情况下为数据库播种。
在测试中使用
传统上,数据fixture定义在测试之外的一个或多个文件中。当使用这些固定装置编写测试时,您的固定装置是一种黑盒.fixture和您正在测试的内容之间没有明确的联系。
Foundry允许每个单独的测试完全遵循AAA(“安排”,“行动”,“断言”)测试模式。在每个测试的开始使用“工厂”创建fixture。您只创建适用于测试的fixture。此外,这些fixture只使用测试所需的属性创建——不适用的属性用随机数据填充。所创建的fixture对象被包装在一个“代理”中,该“代理”有助于预处理和后断言。
让我们来看一个例子:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
公共函数test_can_post_a_comment():无效{/ / 1。“安排”$帖子= PostFactory::新()//新的邮局->(出版)//使帖子处于“已发布”状态->创建([//实例化Post对象并保存“鼻涕虫”= >“发布”//这个测试只需要slug字段,其他字段都是随机数据]);/ / 1。“Pre-Assertions”$这->assertCount (0,$帖子->getComments ());/ / 2。“行动”静态::ensureKernelShutdown ();//创建工厂引导内核;在创建客户端之前关闭$客户端=静态::createClient ();$客户端->请求(“得到”,“/文章/发布”);//注意来自排列步骤的分段$客户端->submitForm (“添加”, (“评论[名字]”= >“约翰。”,的评论(身体)= >“我的评论”]);/ / 3。“维护”自我::assertResponseRedirects (“/文章/发布”);$这->assertCount (1,$帖子->refresh ()->getComments ());//从数据库中刷新$post并调用->getComments()CommentFactory::assert ()->存在([//理论存储库断言“名字”= >“约翰。”,“身体”= >“我的评论”]);}
在您的TestCase中启用Foundry
添加工厂
使用工厂的测试的特性:
12 3 4 5 6 7 8 9 10 11 12 13 14 15
使用应用程序\工厂\PostFactory;使用Zenstruck\铸造\测试\工厂;使用ob娱乐下载\包\FrameworkBundle\测试\WebTestCase;类MyTest扩展WebTestCase{使用工厂;公共函数test_1():无效{$帖子= PostFactory::createOne ();/ /……}}
数据库重启
这个库要求在每次测试之前重置数据库。打包的ResetDatabase
Trait会帮你处理这个问题。
1 2 3 4 5 6 7 8 9 10
使用Zenstruck\铸造\测试\工厂;使用Zenstruck\铸造\测试\ResetDatabase;使用ob娱乐下载\包\FrameworkBundle\测试\WebTestCase;类MyTest扩展WebTestCase{使用ResetDatabase,工厂;/ /……}
在第一次测试之前使用ResetDatabase
Trait,它将删除(如果存在)并创建测试数据库。然后,默认情况下,在每次测试之前,它使用原则:模式:下降
/原则:模式:创建
.
或者,您也可以通过修改reset_mode
配置文件中的选项。当使用这个时模式,在每次测试之前,数据库被删除/创建,您的迁移运行(通过原则:迁移:迁移
).这种模式确实会使您的测试套件变慢(特别是当您有很多迁移时)。强烈推荐使用DamaDoctrineTestBundle提高速度。当该bundle被启用时,该套件只会删除/创建和迁移数据库一次。
提示
为使用工厂的测试创建一个基本测试用例,以避免向每个测试用例添加特征。
提示
如果你的测试没有坚持他们创建的对象,这些测试特性不是必需的。
默认情况下,ResetDatabase
重置默认配置连接的数据库和默认配置对象管理器的模式。要自定义要重置的连接和对象管理器(或重置多个连接/管理器),使用bundle的配置:
- YAML
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#配置/包/ zenstruck_foundry.yamlwhen@dev:关于在测试环境中共享这个,请参阅Bundle配置部分zenstruck_foundry:database_resetter:orm:连接:-orm_connection_1-orm_connection_2object_managers:-orm_object_manager_1-orm_object_manager_2reset_mode:模式odm:object_managers:-odm_object_manager_1-odm_object_manager_2
对象代理
由工厂创建的对象被包装在一个特殊的代理对象。这些对象允许你的教义实体拥有活动记录就像行为:
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21
使用应用程序\工厂\PostFactory;$帖子= PostFactory::createOne ([“标题”= >“我的名字”]);// Zenstruck\Foundry\Proxy实例//获取包装对象$realPost=$帖子->对象();// Post的实例//调用任何Post方法$帖子->getTitle ();// "我的头衔"//设置属性并保存到数据库$帖子->setTitle (“新标题”);$帖子->save ();//从数据库刷新$帖子->refresh ();//从数据库删除$帖子->remove ();$帖子->存储库();//存储库代理包装PostRepository(参见下面的存储库代理部分)
力设置
对象代理具有helper方法来访问所包装对象的非公共属性:
1 2 3 4 5
//设置私有/受保护属性$帖子->forceSet (“createdAt”,新\ DateTime ());//获取私有/受保护的属性$帖子->forceGet (“createdAt”);
自动刷新
对象代理具有启用的选项自动刷新这样就不需要打电话了- > refresh ()
在调用底层对象上的方法之前。在启用自动刷新时,大多数对代理对象的调用都会首先刷新数据库中的包装对象。
1 2 3 4 5 6 7 8 9 10
使用应用程序\工厂\PostFactory;$帖子= PostFactory::新([“标题”= >“标题”])->create ()->enableAutoRefresh ();/ /……将$post标题更改为“New title”的逻辑(就像你的功能测试一样)$帖子->getTitle ();// "New Title"(相当于$post->refresh()->getTitle()))
在未启用自动刷新的情况下,上述调用post - > getTitle ()
将返回“原标题”。
请注意
使用自动刷新时需要注意的一种情况是,所有方法都首先刷新对象。如果通过多个方法(或多个force-set)改变对象的状态,则会抛出一个"unsaved changes"异常:
1 2 3 4 5 6 7 8 9
使用应用程序\工厂\PostFactory;$帖子= PostFactory::新([“标题”= >“标题”,“身体”= >“原来的身体”])->create ()->enableAutoRefresh ();$帖子->setTitle (“新标题”);$帖子->setBody (“新的身体”);//由于上面$post的“未保存的更改”而抛出异常
为了克服这个问题,你需要先禁用自动刷新,然后在进行/保存更改后重新启用:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
使用应用程序\实体\帖子;使用应用程序\工厂\PostFactory;$帖子= PostFactory::新([“标题”= >“标题”,“身体”= >“原来的身体”])->create ()->enableAutoRefresh ();$帖子->disableAutoRefresh ();$帖子->setTitle (“新标题”);//或使用->forceSet('title', 'New title')$帖子->setBody (“新的身体”);//或使用->forceSet('body', 'New body')$帖子->enableAutoRefresh ();$帖子->save ();$帖子->getBody ();// "New Body"$帖子->getTitle ();// "New Title"//或者,使用->withoutAutoRefresh()帮助器,它首先禁用自动刷新,然后重新启用//执行回调。$帖子->withoutAutoRefresh (函数(文章$帖子){//可以将Post或Proxy传递给回调$帖子->setTitle (“新标题”);$帖子->setBody (“新的身体”);});$帖子->save ();//如果强制设置属性,你可以使用->forceSetAll()帮助:$帖子->forceSetAll ([“标题”= >“新标题”,“身体”= >“新的身体”]);$帖子->save ();
请注意
您可以全局启用/禁用自动刷新,以默认或不自动刷新每个代理。启用后,您将不得不这样做选择退出自动刷新。
- YAML
1 2 3 4
#配置/包/ zenstruck_foundry.yamlwhen@dev:关于在测试环境中共享这个,请参阅Bundle配置部分zenstruck_foundry:auto_refresh_proxies:真正的/错误
库代理
此库提供库代理包装对象存储库以提供有用的断言和方法:
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
使用应用程序\实体\帖子;使用应用程序\工厂\PostFactory;使用函数Zenstruck\铸造\存储库;//封装PostRepository的RepositoryProxy实例$存储库= PostFactory::存储库();//替代上面的代理存储库,你没有创建模型工厂$存储库=库(职位::类);//所有返回的对象都被代理$存储库->内部();//真正的“包装”存储库$存储库->count ();//数据库表的行数计数($存储库);//相当于上面(RepositoryProxy实现\Countable)$存储库->第();//获取第一个对象(假设一个自动递增的"id"列)$存储库->第一次(“createdAt”);//假设"createdAt"是一个datetime列,它将返回最新的对象$存储库->最后();//获取最后一个对象(假设一个自动递增的"id"列)$存储库->最后一个(“createdAt”);//假设"createdAt"是一个datetime列,将返回最古老的对象$存储库->截断();//删除数据库表中的所有行$存储库->随机();//获取一个随机对象$存储库->随机([“作者”= >“凯文”]);//获取一个随机的对象$存储库->randomSet (5);//获取5个随机对象$存储库->randomSet (5, (“作者”= >“凯文”]);//获取5个随机对象$存储库->randomRange (0,5);//获取0-5个随机对象$存储库->randomRange (0,5, (“作者”= >“凯文”]);//获取0-5个随机对象// instance of ObjectRepository -所有返回的对象都被代理$存储库->找到(1);/ /代理| |空$存储库->找到([“标题”= >“我的名字”]);/ /代理| |空$存储库->findOneBy ([“标题”= >“我的名字”]);/ /代理| |空$存储库->findAll ();/ /代理[]|文章[]iterator_to_array ($存储库);//相当于上面(RepositoryProxy实现\IteratorAggregate)$存储库->findBy ([“标题”= >“我的名字”]);/ /代理[]|文章[]//可以调用底层存储库上的方法-返回的对象是代理的$存储库->findOneByTitle (“我的名字”);/ /代理| |空
断言
对象代理和您的ModelFactory都有有用的PHPUnit断言:
12 3 4 5 6 7 8 9 10 11 12 13 14 15
使用应用程序\工厂\PostFactory;$帖子= PostFactory::createOne ();$帖子->assertPersisted ();$帖子->assertNotPersisted ();PostFactory::assert ()->空();PostFactory::assert ()->计数(3.);PostFactory::assert ()->countGreaterThan (3.);PostFactory::assert ()->countGreaterThanOrEqual (3.);PostFactory::assert ()->countLessThan (3.);PostFactory::assert ()->countLessThanOrEqual (3.);PostFactory::assert ()->存在([“标题”= >“我的名字”]);PostFactory::assert ()->notExists ([“标题”= >“我的名字”]);
全局状态
如果您有一个需要用于所有测试的初始数据库状态,您可以在bundle的配置中设置它。公认的价值是:故事即服务、“全局”故事和可调用服务。
- YAML
1 2 3 4 5 6 7 8
#配置/包/ zenstruck_foundry.yamlwhen@test:关于在测试环境中共享这个,请参阅Bundle配置部分zenstruck_foundry:global_state:-应用\ \ StoryThatIsAService故事-应用\ \ GlobalStory故事-invokable.service#使用::invoke()只是一个服务-...
请注意
你仍然可以访问故事的状态为全球国家故事在测试中,它们仍然只加载一次。
请注意
的ResetDatabaseTrait在使用全局状态时是必需的。
PHPUnit数据提供者
有可能使用工厂PHPUnit数据提供程序:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
使用应用程序\工厂\PostFactory;/ * * *@dataProviderpostDataProvider * /公共函数test_post_via_data_provider(PostFactory$工厂):无效{$帖子=$工厂->create ();/ /……}公共静态函数postDataProvider():可迭代的{收益率[PostFactory::新());收益率[PostFactory::新()->发表()];}
请注意
的实例,确保您的数据提供程序只返回ModelFactory
你也不要试着打电话- > create ()
在他们身上。数据提供程序是在phpunit进程的早期,在Foundry启动之前计算的。
请注意
出于与上面相同的原因,它不可能使用工厂即服务使用必需的构造函数参数(容器还不可用)。
提示
ModelFactory::新()- >许多()
而且ModelFactory::新()- >序列()
返回一个特殊的FactoryCollection
对象,可用于生成数据提供程序:
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21
使用应用程序\工厂\PostFactory;/ * * *@dataProviderpostDataProvider * /公共函数test_post_via_data_provider(PostFactory$工厂):无效{$工厂->create ();/ /……}公共静态函数postDataProvider():可迭代的{收益率从PostFactory::新()->序列([[“标题”= >“foo”]、[“标题”= >“酒吧”],])->asDataProvider ();}
的FactoryCollection
也可以直接传递给测试用例,以便在同一个测试中有几个可用的对象:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
使用应用程序\工厂\PostFactory;/ * * *@dataProviderpostDataProvider * /公共函数test_post_via_data_provider(FactoryCollection$factoryCollection):无效{$factoryCollection->create ();/ /……}公共静态函数postDataProvider():可迭代的{//为第一个测试用例创建3个post收益率PostFactory::新()->序列([[“标题”= >“foo 1”]、[“标题”= >“酒吧1 ']、[“标题”= >“巴兹1”],]);//为第二个测试用例创建2个post收益率PostFactory::新()->序列([[“标题”= >“foo 2”]、[“标题”= >《酒吧2》],]);}
性能
以下是提高测试套件速度的可能选项。
DAMADoctrineTestBundle
该库与DAMADoctrineTestBundle将每个测试包装在一个事务中,这将极大地减少测试时间。启用这个bundle后,该库的测试套件运行速度提高了5倍。
按照其文档进行安装。欧宝官网下载app铸造的ResetDatabase
Trait在使用bundle时进行检测并相应地进行调整。在运行测试套件之前仍然重置数据库,但在每次测试之前(仅在第一次测试之前)不会重置模式。
请注意
如果使用全局状态,在运行测试套件之前,它被持久化到数据库中(而不是在事务中)。如果您有一个复杂的全局状态,这可以进一步提高测试速度。
谨慎
使用全局状态不支持在使用DAMADoctrineTestBundle时同时创建ORM和ODM工厂。
杂项
运行测试时禁用调试模式。在你的
.env.test
文件,可以设置APP_DEBUG = 0
在没有调试模式的情况下运行测试。这可以大大加快测试速度。在运行测试套件之前,您需要确保缓存已被清除。最好的地方是在你的测试/ bootstrap.php
:1 2 3 4 5 6
/ /测试/ bootstrap.php/ /……如果(假= = =(保龄球)$_SERVER[“APP_DEBUG”) {//确保刷新缓存(新ob娱乐下载Symfony \文件系统组件\ \文件系统())->remove (__DIR__.“/ . . / var /缓存/测试”);}
减少密码编码器工作因素.如果您有很多使用编码密码的测试,这将导致这些测试不必要地慢。你可以通过减少。来提高速度工作因素编码器:
1 2 3 4 5 6 7 8 9
#配置/包/测试/ security.yaml编码器:在这里使用你的用户类名应用实体\ \用户:这个值应该与config/packages/security.yaml中的值相同算法:汽车成本:4# bcrypt的最低可能值time_cost:3.#氩的最低可能值memory_cost:10#氩的最低可能值
预先编码用户密码的已知值via
bin /控制台安全:encode-password
然后把它放进去ModelFactory: getDefaults ()
.将已知值加为a常量
关于你的工厂:12 3 4 5 6 7 8 9 10 11 12
类UserFactory扩展ModelFactory{公共常量DEFAULT_PASSWORD =“1234”;//用于创建下面的预编码版本的密码受保护的函数getDefaults():数组{返回[/ /……“密码”= >“argon2id v = 19美元= 65536美元,t = 4, p = 1 pLFF3D2gnvDmxMuuqH4BrA 3美元vkfv0cw + 6 eanspq9btvayc + jCOqrmWRstInB2fRPeQ ',);}}
现在,在您的测试中,当您需要访问使用
UserFactory
,使用UserFactory: DEFAULT_PASSWORD
.
没有测试
Foundry可以用于标准的PHPUnit单元测试(只是扩展的TestCase)PHPUnit) \ \ TestCase的框架
而不是ob娱乐下载
).这些测试仍然需要使用工厂
trait可以引导Foundry,但是没有可用的学说。在这些测试中创建的工厂将不会被持久化(调用- > withoutPersisting ()
没有必要)。因为这个包在这些测试中不可用,所以您拥有的任何包配置都不会被拾取。
12 3 4 5 6 7 8 9 10 11 12 13 14 15
使用应用程序\工厂\PostFactory;使用PHPUnit)\框架\TestCase;使用Zenstruck\铸造\测试\工厂;类MyUnitTest扩展TestCase{使用工厂;公共函数some_test():无效{$帖子= PostFactory::createOne ();// $post不持久化到数据库}}
您需要手动配置Foundry。不幸的是,这可能意味着复制您的bundle配置。
1 2 3 4 5 6 7 8 9 10
/ /测试/ bootstrap.php/ /……Zenstruck \铸造\ \ TestState测试::配置(实例器:新Zenstruck \铸造\ Instantiator ())->withoutConstructor ()->allowExtraAttributes ()->alwaysForceProperties(), faker: faker \Factory::创建(“fr_FR”));
故事
如果你找到你的测试,故事是有用的安排步骤是变得复杂(加载大量fixture)或在测试和/或开发fixture之间复制逻辑。它们用于提取特定的数据库状态成一个故事.故事可以加载到fixture和测试中,它们也可以依赖于其他故事。
使用maker命令创建一个故事:
1
$bin/console make:story Post
请注意
创建PostStory.php
在src /故事
,添加——测试
要创建的标志测试/故事
.
修改构建方法设置此故事的状态:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/ / src /故事/ PostStory.php名称空间应用程序\故事;使用应用程序\工厂\CategoryFactory;使用应用程序\工厂\PostFactory;使用应用程序\工厂\TagFactory;使用Zenstruck\铸造\故事;最后类PostStory扩展故事{公共函数构建():无效{//创建10个类别CategoryFactory::createMany (10);//创建20个标签TagFactory::createMany (20.);//创建50个PostPostFactory::createMany (50,函数(){返回[//每个帖子都有一个随机的类别(上面创建的)“类别”= > CategoryFactory::随机(),//每个Post的Tag在0到6之间(上面创建的)“标签”= > TagFactory::randomRange (0,6),);});}}
在您的测试、开发装置或甚至其他故事中使用新的故事:
1 2 3
PostStory::load ();//加载PostStory::build()中定义的状态PostStory::load ();//什么都不做-已经加载
请注意
故事中持久化的对象在每次测试后都被清除(除非它是一个全球国家故事).
故事即服务
如果你的故事需要依赖,你可以将它们定义为服务:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/ / src /故事/ PostStory.php名称空间应用程序\故事;使用应用程序\工厂\PostFactory;使用应用程序\服务\ServiceA;使用应用程序\服务\ServiceB;使用Zenstruck\铸造\故事;最后类PostStory扩展故事{私人$serviceA;私人$serviceB;公共函数__construct(ServiceA$serviceA, ServiceB$serviceB){$这->serviceA =$serviceA;$这->serviceB =$serviceB;}公共函数构建():无效{//可以使用$this-> servicb, $this-> servicb在这里帮助建立这个故事}}
如果使用标准的Symfony Flex应ob娱乐下载用,这将是自动连接/自动配置的。如果不是,则注册服务并标记foundry.story
.
请注意
作为服务的故事需要所提供的捆绑包。
故事的状态
的另一个特点故事是他们的能力吗还记得他们创建的稍后被引用的对象:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/ / src /故事/ CategoryStory.php名称空间应用程序\故事;使用应用程序\工厂\CategoryFactory;使用Zenstruck\铸造\故事;最后类CategoryStory扩展故事{公共函数构建():无效{$这->addState (“php”, CategoryFactory::createOne ([“名字”= >“php”)));//当添加为state时,会创建工厂$这->addState (sob娱乐下载ymfony的, CategoryFactory::新([“名字”= >sob娱乐下载ymfony的)));}}
稍后,你可以在创建其他fixture时访问故事的状态:
1 2 3 4
PostFactory::createOne ([“类别”= > CategoryStory::get (“php”)));//或者使用magic方法(功能上与上面相同)PostFactory::createOne ([“类别”= > CategoryStory::php ()));
请注意
故事状态在每次测试之后被清除(除非它是一个全球国家故事).
故事池
故事可以存储(作为状态)池的对象:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/ / src /故事/ ProvinceStory.php名称空间应用程序\故事;使用应用程序\工厂\ProvinceFactory;使用Zenstruck\铸造\故事;最后类ProvinceStory扩展故事{公共函数构建():无效{//添加collection到pool$这->addToPool (“是”, ProvinceFactory::createMany (5, (“国家”= >“是”)));//等价于上面$这->addToPool (“是”, ProvinceFactory::新([“国家”= >“是”])->许多(5));//添加单个对象到池中$这->addToPool (“是”, ProvinceFactory::createOne ([“国家”= >“是”)));//添加单个对象到单个池,并使其可用为"state"$这->addState (“1”, ProvinceFactory::createOne ([“国家”= >“是”]),“是”);}}
对象可以从您的测试、fixture或其他故事中的池中获取:
1 2 3 4
ProvinceStory::getRandom (“是”);//随机省|代理从"be"池ProvinceStory::getRandomSet (“是”,3.);// 3个随机省|代理从"be"池ProvinceStory::getRandomRange (“是”,1,4);//在1到4个随机省|代理从"be"池ProvinceStory::getPool (“是”);//所有省|代理从"be"池
包配置
由于该包打算用于您的dev而且测验环境,您将希望每个环境的配置都匹配。最简单的方法是使用YAML锚与when@dev
/when@test
.这样,只有一个地方可以设置您的配置。
- YAML
1 2 3 4 5 6 7
#配置/包/ zenstruck_foundry.yamlwhen@dev:devzenstruck_foundry:#……把你所有的配置都放在这里when@test:*开发#“从上面复制”配置
完全默认Bundle配置
- YAML
- PHP
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
zenstruck_foundry:#默认是否自动刷新代理(https://github.com/zenstruck/foundry#auto-refresh)auto_refresh_proxies:真正的#配置faker为你的工厂使用。骗子:#更改默认的faker区域设置。地区:零#示例:fr_FR#随机数生成器种子产生相同的假值每次运行种子:零#示例:1234#定制faker服务。服务:零#示例:my_faker#配置工厂使用的默认实例化器。instantiator:是否在实例化过程中调用对象的构造函数。without_constructor:假#是否允许额外属性。allow_extra_attributes:假#是否直接跳过setter并强制设置对象属性(public/private/protected)。always_force_properties:假#自定义实例化器服务服务:零#示例:my_instantiator#配置数据库重置机制database_resetter:# ORM相关配置orm:#连接重置。如果为空,则使用默认连接。连接:[]#对象管理器重置。如果为空,则使用默认管理器。object_managers:[]#重置模式时使用doctrine:schema:update还是迁移。reset_mode:模式# "schema"或"migrate"# ODM相关配置odm:#对象管理器重置。如果为空,则使用默认管理器。object_managers:[]#添加全局状态。global_state:[]