brain / faker
通过 Brain Monkey 为 WordPress 提供 Faker (phpfaker/faker)
Requires
- php: >=7.2
- brain/monkey: ^2.3.1
- fakerphp/faker: ^1.20
Requires (Dev)
- inpsyde/php-coding-standards: ^1.0
- phpunit/phpunit: ^9.5
This package is auto-updated.
Last update: 2024-08-30 01:49:37 UTC
README
使用 Faker 和 Brain Monkey 来提供生成 虚假 WordPress 对象和相关功能的简便方式。
测试设置
参考 Brain Monkey 为 WordPress 的设置,我们可以通过 Brain Faker 的功能扩展它。
class FakerTestCase extends \PHPUnit\Framework\TestCase { use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; /** * @var \Faker\Generator */ protected $faker; /** * @var \Brain\Faker\Providers */ protected $wpFaker; protected function setUp(): void { parent::setUp(); \Brain\Monkey\setUp(); $this->faker = \Brain\faker(); $this->wpFaker = $this->faker->wp(); } protected function tearDown(): void { \Brain\fakerReset(); \Brain\Monkey\tearDown(); parent::tearDown(); } }
除了 Brain Monkey 的常规设置之外,我们在测试用例实例中存储了两个属性
$faker
是一个 Faker 实例,它通过 Brain Faker 功能进行了“扩展”,基本上是一个->wp()
方法$wpFaker
是一个\Brain\Faker\Providers
实例,它是 Brain Faker 提供的所有方法的入口点。
建议在属性上使用文档块,因为 IDE 将能够提供自动完成所有可以调用的 Faker 和 Brain Faker 方法。
对于 README 的其余部分,假设此测试设置,例如,将到处使用 $this->wpFaker
,但只要通过 \Brain\faker()->wp()
获得一个 Faker\Providers
实例,并在每个测试结束时调用 \Brain\fakerReset
,Brain Faker 就会按预期工作。
值得注意的是,与 Brain Monkey 一样,Brain Faker 不需要 PHPUnit,这里使用它只是为了方便。
可以伪造什么
所有将扩展上述基本测试用例类的测试用例类都可以使用 $this->wpFaker
生成
WP_Post
实例,并模拟相关的函数,如get_post
和get_post_field
WP_User
实例,并模拟相关的函数,如get_userdata
、get_user_by
、user_can
等WP_Term
实例,并模拟相关的函数,如get_term
和get_term_by
WP_Comment
实例WP_Site
实例,并模拟相关的函数,如get_site
WP_Post_type
实例,并模拟相关的函数,如get_post_type_object
和post_type_exists
WP_Taxonomy
实例,并模拟相关的函数,如get_taxonomy
和taxonomy_exists
WP_Error
实例
Brain Faker 生成的实例不仅是“虚假”的,因为它们不是来自数据库,而且因为它们实际上是“模拟实例”,即它们是使用 Mockery 获得的。
快速示例
class MyPostCase extends FakerTestCase { public function testPostsCanBeFaked() { $posts = $this->wpFaker->posts(10); static::assertIsArray($posts); static::assertCount(10, $posts); foreach ($posts as $post) { static::assertInstanceOf(\WP_Post::class, $post); static::assertGreaterThanOrEqual(1, $post->ID); static::assertIsString($post->post_title)); static::assertIsString($post->post_content)); static::assertIsArray($post->to_array()); } } }
$this->wpFaker->posts()
,我们用来生成虚假 WP_Post
实例的方法,接受第一个参数为要生成的帖子数。
第二个可选参数可以用来固定生成帖子的一些属性,例如以下代码
$this->wpFaker->posts(10, ['type' => 'page', 'status' => 'publish']);
可以用来获取 10 个帖子,所有帖子类型为“页面”且状态为“发布”。
如果没有提供,所有属性都将随机生成。
除了 $this->wpFaker->posts()
之外,Brain Faker 还提供了 $this->wpFaker->post()
,该方法返回一个模拟的 WP_Post
实例,并且像 posts()
一样,也可以接受一个可选参数,该参数是一个属性数组,用于分配给该实例。
已经说过,$this->wpFaker->posts()
接受的第一个参数是我们想要生成的对象数量。
但是这是可选的,如果没有提供,Brain Faker 将生成一个随机数量的对象(可能是零)。
值得注意的是,调用 $this->wpFaker->posts()
(不带参数)与调用 $this->wpFaker->posts
相同,这通常在 Faker 中发生。
有时,我们可能希望生成一个最小或最大数量的对象,为此,Brain Faker 提供了一组以以下形式的方法
$this->wpFaker->atLeast{$n}Posts()
,例如$this->wpFaker->atLeast6Posts()
$this->wpFaker->atMost{$n}Posts()
,例如$this->wpFaker->atMost20Posts()
请注意,只有当数字在 1 到 5 之间时,才可以用文字拼写,因此以下所有方法都是有效的
$this->wpFaker->atLeastOnePost()
$this->wpFaker->atMostTwoPost()
$this->wpFaker->atLeastThreePosts()
$this->wpFaker->atMostFourPosts()
$this->wpFaker->atLeastFivePosts()
还要注意,当数字是 One
(或 1
)时,实体可以是单数(例如,Post
而不是 Posts
)。
要设置生成实例的最小和最大数量,Brain Faker 提供了一组以以下形式的方法
$this->wpFaker->between{$min}And{$max}Posts()
例如
$this->wpFaker->betweenOneAndThreePosts()
$this->wpFaker->between6And10Posts()
$this->wpFaker->between0AndFourPosts()
所有这些“动态命名”的方法都接受一个可选参数,该参数是一个属性数组,用于分配给生成的帖子
$posts = $this->wpFaker->atLeastTwoPosts(['type' => 'post']); $pages = $this->wpFaker->betweenThreeAnd10Posts(['type' => 'page']);
不仅仅是帖子
上述所有关于帖子的话也适用于其他受支持的对象,事实上 Brain Faker 方法的列表包括
对于 帖子
$this->wpFaker->posts()
$this->wpFaker->atLeast{$n}Posts()
$this->wpFaker->atMosts{$n}Posts()
$this->wpFaker->between{$min}and{$max}Posts()
$this->wpFaker->post()
对于 用户
$this->wpFaker->users()
$this->wpFaker->atLeast{$n}Users()
$this->wpFaker->atMosts{$n}Users()
$this->wpFaker->between{$min}and{$max}Users()
$this->wpFaker->user()
对于 术语
$this->wpFaker->terms()
$this->wpFaker->atLeast{$n}terms()
$this->wpFaker->atMosts{$n}terms()
$this->wpFaker->between{$min}and{$max}Terms()
$this->wpFaker->term()
对于 评论
$this->wpFaker->comments()
$this->wpFaker->atLeast{$n}comments()
$this->wpFaker->atMosts{$n}comments()
$this->wpFaker->between{$min}and{$max}Comments()
$this->wpFaker->comment()
对于 站点
$this->wpFaker->sites()
$this->wpFaker->atLeast{$n}sites()
$this->wpFaker->atMosts{$n}sites()
$this->wpFaker->between{$min}and{$max}Sites()
$this->wpFaker->site()
对于 帖子类型
$this->wpFaker->postTypes()
$this->wpFaker->atLeast{$n}PostTypes()
$this->wpFaker->atMosts{$n}PostTypes()
$this->wpFaker->between{$min}and{$max}PostTypes()
$this->wpFaker->postType()
对于 分类法
$this->wpFaker->taxonomies()
$this->wpFaker->atLeast{$n}Taxonomies()
$this->wpFaker->atMosts{$n}Taxonomies()
$this->wpFaker->between{$min}and{$max}Taxonomies()
$this->wpFaker->taxonomy()
对于 WP_Error
$this->wpFaker->errors()
$this->wpFaker->atLeast{$n}Errors()
$this->wpFaker->atMosts{$n}Errors()
$this->wpFaker->between{$min}and{$max}Errors()
$this->wpFaker->error()
关于返回的实例
对于所有返回的对象,Brain Faker 设置了所有公共属性,这些属性是 真实 WordPress 对象所具有的。
感谢Faker,所有属性都将具有随机但“真实”的值(电子邮件将是电子邮件,URL将是URL,密码将是密码等等)。
在WordPress对象中未声明但通过魔术方法__get
公开的属性,在伪造对象上也是可用的,例如执行$this->wpFaker->user->user_login
是完全有效的,即使user_login
是真实的WP_User
实例通过魔术方法提供的属性。
已经说过,返回的实例是通过Mockery获得的模拟对象。
重要的是要说,这些实例上并非所有方法都进行了模拟。
例如,对于帖子,只有WP_Post::to_array()
方法进行了模拟,但其他方法如WP_Post::filter()
没有模拟,但当然可以“手动”模拟。
例如,以下代码是有效的
$this->wpFaker->post ->shouldReceive('filter') ->once();
Brain Faker模拟的方法当然会因对象而异。
除此之外,Brain Faker还模拟了一些WordPress“相关函数”。
以下是Brain Faker为其支持的每种对象模拟的完整方法和函数列表。
什么是模拟
帖子模拟的内容
在创建伪造的WP_Post
对象时,Brain Faker使用以下模拟
- 所有的
WP_Post
对象属性,包括WordPress通过__get
提供的属性,如page_template
; WP_Post::to_array()
方法,其工作方式与WordPress版本完全相同;get_post
函数;get_post_field
函数;
例如
class MyPostCase extends FakerTestCase { public function testGetPostCanBeFaked() { $this->wpFaker->post(['id' => 42, 'title' => 'The Answer']); static::assertSame('The Answer', get_post(42)->post_title); static::assertFalse(get_post(1)); static::assertIsString(get_post_field('post_content', 42)); } }
当用伪造帖子的ID调用时(因为我们知道它是通过提供的数组强制执行的),get_post
返回我们生成的伪造帖子。
然而,当用另一个ID调用时,它返回false
,就像WordPress对未找到的帖子所做的那样。
模拟版本的get_post
将能够识别测试(或在任何情况下在调用Brain\fakerReset()
之前)内创建的所有帖子,并将它们正确解析,对于未创建的帖子返回false。
请注意,get_post
返回的对象与伪造的对象完全可比较,但它不是同一个实例,即严格的相等性比较(===
)将失败。
对于get_post_field
也是如此,Brain Faker模拟的所有其他函数也以类似的方式工作。
用户模拟的内容
在创建伪造的WP_User
对象时,Brain Faker使用以下模拟
- 所有的
WP_User
对象属性,包括WordPress通过__get
提供的许多属性,如first_name
、last_name
、user_login
等; WP_User::to_array()
方法;WP_User::exists()
方法;WP_User::get_site_id()
方法;WP_User::has_cap()
方法;get_user_data()
函数get_user_by()
函数user_can()
函数
此外,伪造的WP_User
实例是Brain Faker创建的唯一具有WordPress对象没有的附加方法的伪造对象,即__monkeyMakeCurrent()
。
当调用时,__monkeyMakeCurrent()
还将模拟以下函数
get_current_user_id
,将返回调用__monkeyMakeCurrent()
的实例的IDwp_get_current_user
,将返回调用__monkeyMakeCurrent()
的实例current_user_can
,将调用实例上的(模拟的)has_cap
方法,该实例上调用__monkeyMakeCurrent()
这非常强大,因为只需要一行代码就可以模拟大量WordPress代码,而不需要加载WordPress。
更甚者,考虑到伪造的 WP_User
实例以非常类似于真实 WordPress 对象的方式模拟(这对所有伪造对象都适用),例如角色和能力将非常“真实”。
例如,考虑以下代码
class MyUserCase extends FakerTestCase { public function testCurrentUserCanBeFaked() { $this->wpFaker->user(['role' => 'editor'])->__monkeyMakeCurrent(); static::assertTrue(current_user_can('edit_others_pages')); } }
术语的模拟是什么
在创建伪造的 WP_Term
对象时,Brain Faker 创建具有以下属性的模拟:
- 所有
WP_Term
对象的属性; WP_Term::to_array()
方法;get_term
函数,但仅当调用带有匹配生成的实例的参数时;get_term_by
函数,但仅当调用带有匹配生成的实例的参数时;
评论的模拟是什么
在创建伪造的 WP_Comment
对象时,Brain Faker 创建具有以下属性的模拟:
- 所有
WP_Comment
对象的属性; WP_Term::to_array()
方法;
站点的模拟是什么
在创建伪造的 WP_Site
对象时,Brain Faker 创建具有以下属性的模拟:
- 所有
WP_Site
对象的属性,包括 WordPress 通过__get
提供的属性; WP_Site::to_array()
方法;get_site()
函数,但仅当调用带有生成实例的 ID 时;
税号的模拟是什么
在创建伪造的 WP_Taxonomy
对象时,Brain Faker 创建具有以下属性的模拟:
- 所有
WP_Taxonomy
对象的属性; get_taxonomy()
函数taxonomy_exists()
函数
帖子类型的模拟是什么
在创建伪造的 WP_Post_Type
对象时,Brain Faker 创建具有以下属性的模拟:
- 所有
WP_Post_Type
对象的属性; get_post_type_object()
函数post_type_exists()
函数
错误的模拟是什么
在创建伪造的 WP_Error
对象时,Brain Faker 创建具有以下属性的模拟:
- 所有
WP_Error
对象的属性,但值为空; - 所有
WP_Error
公共方法;
伪造的 WP_Error
实例是 Brain Faker 创建的唯一一个属性不是“随机填充”而是完全模拟的模拟对象,因此可以将其用作 WordPress 对象。
想象一些类似这样的 WordPress 代码
function maybeAddError(\WP_Error $error): \WP_Error { if (is_error_there()) { $error->add('code', 'A message', 'some data'); } return $error; }
使用 Brain Faker(和 Brain Monkey)我们可以这样测试
class MyErrorCase extends FakerTestCase { /** * Test that error have expected message and data * when `is_error_there` returns true */ public function testMaybeAddErrorWhenErrorIsThere() { \Brain\Monkey\Functions\when('is_error_there')->justReturn(true); $error = maybeAddError($this->wpFaker->error); static::assertTrue($error->has_errors()); static::assertSame('A message', $error->get_error_message()); static::assertSame('some data', $error->get_error_data()); } /** * Test that error is empty when `is_error_there` returns false */ public function testMaybeAddErrorWhenErrorIsNotThere() { \Brain\Monkey\Functions\when('is_error_there')->justReturn(false); $error = maybeAddError($this->wpFaker->error); static::assertFalse($error->has_errors()); static::assertSame([], $error->get_error_messages()); } }
请注意,即使所有 \WP_Error
方法都进行了模拟,测试中仍然可以覆盖已模拟的方法(这对 Brain Faker 生成的所有伪造对象都适用)。
高级主题
关于 ID 的唯一性
对于支持 ID 的对象(帖子、用户、术语、评论),除非在选项数组中给出,否则会随机生成一个 ID。
值得注意的是,这些随机生成的 ID 在每个测试中是唯一的(或者至少在调用 Brain\fakerReset
之前是这样)。对于用户来说,除了 ID 之外,当随机生成时电子邮件和登录也是唯一的。
例如,执行 $this->wpFaker->atLeast50Users()
时,Brain Faker 将创建至少 50 个模拟用户实例,每个实例具有不同的 ID、电子邮件和用户登录。
此功能基于 Faker unique()
修饰符。
如 Faker 文档所述,唯一生成器可以被“重置”。要在使用 Brain Faker 时执行此操作,可以调用 $this->wpFaker->__resetUnique()
。
请注意,手动调用 __resetUnique()
(它会在调用 Brain\fakerReset
时自动调用)可能与 Brain Monkey 的模拟函数冲突,因此应避免使用除非确切知道自己在做什么。
本地化的 Faker
Faker 支持其一些提供者的本地化。
要获取 Faker 的本地化版本,在使用 Brain Faker 时,可以将所需的区域设置传递给 \Brain\faker()
函数。
例如
protected function setUp(): void { parent::setUp(); \Brain\Monkey\setUp(); $this->faker = \Brain\faker('fr_FR'); $this->wpFaker = $this->wpFaker->wp(); }
当然,可以拥有多个 Faker(和 Brain Faker)实例,用于不同的区域设置,也可以不在 setUp
中实例化它们,而是在各个测试中实例化。
即使在那种情况下,在测试结束时只调用一次\Brain\fakerReset()
也是可以的。
覆盖 Brain Faker 方法和方法
所有 Brain Faker 模拟生成的对象的方法都可以轻松覆盖。
例如
class MyUserCase extends FakerTestCase { public function testUserCanBeMadeNotExistent() { $user = $this->wpFaker->user(['id' => 123]); $user->shouldReceive('exist')->once()->andReturn(false); static::assertFalse($user->exists()); } }
在上面的例子中,生成的用户已经有一个模拟的 exist
方法,该方法会返回 true,因为 ID 大于零。
然而,我们能够覆盖方法期望并使其返回 false。
这是返回实例实际上是模拟对象的一大优势。
不幸的是,由于底层 Brain Monkey 的限制,这种方法不能用于 Brain Faker 模拟的函数。
例如
class MyUserCase extends FakerTestCase { public function testBrainMonkeyFunctionsExpectIsIgnored() { $this->wpFaker->user(['id' => 123]); Brain\Monkey\Functions\expect('get_userdata') ->with(123) ->andReturn(false); static::assertSame(123, get_userdata(123)->ID); } }
上面的代码片段显示了如何忽略使用 Brain Monkey 对 get_userdata
的“手动”模拟,因此当调用其 ID 时,get_userdata
仍然返回模拟的用户。
为了解决这个问题,Brain Faker 提供了一个方法 $this->wpFaker->__monkeyFunction()
,可以用来替换 Brain Faker 模拟的函数的期望。
上面的测试可以重写如下
class MyUserCase extends FakerTestCase { public function testGetUserDataCanBeOverridden() { $this->wpFaker->user(['id' => 123]); $this->wpFaker->__monkeyFunction('get_userdata') ->with(123) ->andReturn(false); static::assertFalse(get_userdata(123)); } }
需要注意的唯一一点是,__monkeyFunction
必须在创建模拟对象之后调用。
这似乎假设,在使用 Brain Faker 时,应该记住它模拟的所有函数,因此应该使用 $this->wpFaker->__monkeyFunction()
而不是 Brain\Monkey\Functions\expect
来模拟它们。
这不是真的。
$this->wpFaker->__monkeyFunction()
总是可以用作 Brain\Monkey\Functions\expect
的替代品,实际上,当与尚未被 Brain Faker 模拟的函数一起使用时,它将作为 Brain\Monkey\Functions\expect
的别名,因此当在测试中使用 Brain Faker 模拟函数时,使用 $this->wpFaker->__monkeyFunction()
可能是个好主意。
安装、要求、许可
Brain Faker 在 MIT 许可下发布。
它需要 PHP 7.1+
可以通过 Composer 安装,在 packagist.org 上作为 brain/faker
提供。
通过 Composer 需要
fzaninotto/Faker
(MIT)brain/monkey
(MIT)mockery/mockery
(BSD-3-Clause) - 由 Brain Monkey 需要antecedent/patchwork
(MIT) - 由 Brain Monkey 需要