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_fieldWP_User实例,并模拟相关的函数,如get_userdata、get_user_by、user_can等WP_Term实例,并模拟相关的函数,如get_term和get_term_byWP_Comment实例WP_Site实例,并模拟相关的函数,如get_siteWP_Post_type实例,并模拟相关的函数,如get_post_type_object和post_type_existsWP_Taxonomy实例,并模拟相关的函数,如get_taxonomy和taxonomy_existsWP_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 需要