加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Laravel factory 使用指引

发布时间:2020-12-14 19:33:34 所属栏目:大数据 来源:网络整理
导读:如果你想为你的 Laravel 项目写一些测试,那么你可能需要在某个时候编写一些工厂模式。 当我第一次听到工厂一词时,我不知道它的含义和作用,更不用说了解它们可以为你的测试带来的好处了。 假设你有一个产品 Controller,该控制器具有一种存储方法来保存新

如果你想为你的 Laravel 项目写一些测试,那么你可能需要在某个时候编写一些工厂模式。 当我第一次听到工厂一词时,我不知道它的含义和作用,更不用说了解它们可以为你的测试带来的好处了。

假设你有一个产品 Controller,该控制器具有一种存储方法来保存新产品的详细信息。 产品可能具有产品代码,标题,价格,描述和标签等属性,这些都在请求中发送到 store 方法。

?

如果你想测试这个 endpoint,可以创建一个属性数组,然后在 POST 请求中发送它

$product = [
    'product_code' => 'ABC123','title' => 'My Amazing Product','price' => 100,'description' => 'This product will change the way you wash your dishes forever','tagline' => 'Voted best in category'
];

$response = $this->post(route('products.store'),$product);

// 你的断言
$response->assertSuccessful();

这么做没问题。

?

但是如果你想在另一个测试中使用该 product,比如测试更新 product,你不得不在下一个测试方法中复制该数组, 或者可以将其提取到测试的 setUp () 方法中 并使其成为 $this->product 以重复利用。

?

如果你还有另一个测试类要测试将 product 添加到 category 中,那你该怎么办?怎样才能重用你的产品代码?你会如何定义不同模型之间的关系? 幸运的是,工厂模式可以解决这些问题。

Creating a factory

你可以通过创建相应的工厂方法来产生你所需要的数据。 这里提供了一个 artisan 命令可以帮助你快速的、根据你的模型创建对应的工厂方法。

php artisan make:factory ProductFactory --model=Product

执行上面命令后,你会在 database/factories 目录下看到一个以你的 Product 模型为基础的,名为 ProductFactory.php 的文件,你可以通过自定义字段名,以及该字段需要的值来获取你需要的数据。下面是一个例子:

use IlluminateSupportStr;
use FakerGenerator as Faker;

$factory->define(AppProduct::class,function (Faker $faker) {
    return [
        'product_code' => 'ABC123','tagline' => 'Voted best in category'
    ];
});

使用 Faker 定义假数据

我们可以使用先前定义的数组中的静态值,但是模型工厂允许我们使用 Faker 生成一些假数据,这样每次生成新模型时测试数据都不一样。

所以对于商品,我们可以使用 numerify 之类的东西来生成不同的商品编号。 这将生成一个以 ABC 开头的代码,后跟三位数字,以代替散列。

?

'product_code' => $faker->numerify('ABC###')

?

如果我们需要要确保商品编码唯一,该怎么办? Faker 有一个 unique 方法,可以确保生成的内容不在表中存在。

?

'product_code' => $faker->unique()->numerify('ABC###')

对于标题,我们可以使用 words 方法来生成一些单词。 如果您想要一个单词数组,则只需要声明您想要多少个单词,但是当我们想要一些产品文本时,我们将 true 添加为第二个参数。

'title' => $faker->words(3,true)

对于价格,我们可以使用 randomNumber 方法,但是作为货币,我们可能希望保留数字小数点后两位,因此我们将使用 randomFloat 方法。 我们还需要限制最小值和最大值,因此我们可以将它们作为下两个参数传递。

?

'price' => $faker->randomFloat(2,10,100)

对于商品描述,我们可以再次使用 words 方法并将其长度设置为更大的值,也可以使用 paragraph,但是可以使用 realText 获得一些看起来更逼真的文本。 我们需要设置所需字符的最大长度。 可以说,在我们的情况下,最多 200 个字符是可以的。

'description' => $faker->realText(200)

最后,对于品牌,我们可以使用比单词或真实文本更有趣的东西,称为流行短语。

'tagline' => $faker->catchPhrase

这是我们更新的 ProductFactory。

use IlluminateSupportStr;
use FakerGenerator as Faker;

$factory->define(AppProduct::class,function (Faker $faker) {
    return [
        'product_code' => $faker->unique()->numerify('ABC###'),'title' => $faker->words(3,true),'price' => $faker->randomFloat(2,100),'description' => $faker->realText(200),'tagline' => $faker->catchPhrase
    ];
});

因此,现在我们有了模型工厂,可以通过模型工厂助手来更新测试以使用它。

$product = factory(AppProduct::class)->make();
$response = $this->post(route('products.store'),$product->toArray());

$response->assertSuccessful();

在此示例中,有两点需要注意。

?

首先,我们使用 factory()->make() 而非 factory()->create()。它们可能听起来很相似,但是 make 将创建一个新的模型供你在测试中使用,而 create 将创建它并将其持久化到你的数据库中。如果 product 的代码中有唯一性验证,使用 create 可能会导致问题,即当数据库中已经有对应 product 时 create 操作会失败。

?

第二点需要注意的是 $this->post() 期望第二个参数是一个数组,因此我们必须在末尾使用 $product->toArray() 方法把它从对象转换成数组。

工厂状态

这似乎达到了我们的要求,但是现在我们想给 product 加一个标记表示它缺货了。将字段添加到数据库后,我们可以使用新字段更新 product 工厂。

'out_of_stock' => $faker->boolean()

这个方法会把缺货标记随机设置为 true 或 false。

?

但是,如果我们想创建一种总是缺货的 product 怎么办?一种方法是在测试中使用工厂助手时覆盖该值。

?

$product = factory(AppProduct::class)->make(['out_of_stock' => true]);

?

如果我们想使代码更具可重用性,我们可以在工厂中创建一个状态。 state 方法将模型设置为第一个参数,将状态名称设置为第二个参数,将要覆盖的值设置为第三个参数。

$factory->state(AppProduct::class,'out_of_stock',[
    'out_of_stock' => true
]);

?

在我们的测试中,我们可以调用工厂,然后在调用 make () 之前应用状态。

?

$product = factory(AppProduct::class)->states('out_of_stock')->make();

工厂模式真正强大的地方在于当我们在工厂中具有多个状态时,它们可以同时应用。 例如,如果我们有一个状态表示某个 product 是免费的,我们可以覆盖它的价格。

$factory->state(AppProduct::class,'free',[
    'price' => 0.00
]);

所以,当我们想要一个缺货且免费的 product 时,在测试中可以对它同时应用这两种状态。

?

$product = factory(AppProduct::class)->states(['out_of_stock','free')->make();

?

制作多个模型

?

另一个小提示,假如我们想要 10 个 product 而不是 1 个,我们不需要调用 10 次工厂,只需要在工厂助手中加一个数量作为第二个参数,它就会自动为我们生成 10 个 product。

?

$products = factory(AppProduct::class,10)->make();

?

工厂中的关系

?

我们对 product 的测试进行得很顺利,但是现在我们有一个属于某个 category 下的产品。工厂模式允许我们使用另一个工厂来测试关系。

?

将 category 表添加到数据库中并定义 product 和 category 模型的关系后,我们就可以建立 category 工厂。

?

php artisan make:factory CategoryFactory --model=Category

?

为简单起见,category 只有标题和描述两个字段,因此我们可以用 word 生成标题,用 realText 生成描述。

?

use IlluminateSupportStr;
use FakerGenerator as Faker;

$factory->define(AppCategory::class,function (Faker $faker) {
    return [
        'title' => $faker->word,'description' => $faker->realText(100)
    ];
});

?

现在,我们可以将 category_id 添加到 product 工厂,但是如何将 product 和 category 关联起来?

如何通过 Factories 创建多条数据

?

开发中,我们可能需要获取多条数据,这时候可以通过传递 factory 第二个参数来实现。下面是例子:

?

$products = factory(AppProduct::class,10)->make();

?

如何通过 Factories 创建有关联的数据

?

现在产品数据的产生已经没什么问题了,但是现在我们想要获取某个分类下的数据,要怎么办呢?在 Factories 中我们可以使用另一个工厂类来达到数据关联的效果。

?

为了获取某分类下的产品,我们需要一个 category 工厂类来创建相应的 category 数据。我们可以通过以下命令创建对应的工厂类:

?

php artisan make:factory CategoryFactory --model=Category

?

为了演示方便,我们的 category 只需要标题和描述两个字段,我们可以用 $faker->word 创建标题数据,用 $faker->realText(100) 来创建描述数据。

?

use IlluminateSupportStr;
use FakerGenerator as Faker;

$factory->define(AppCategory::class,'description' => $faker->realText(100)
    ];
});

?

现在我们已经通过 category 工厂类来产生分类数据,但是要如何将产品和分类数据关联呢?

?

我们可以使用刚在 Product factory 中创建的工厂,而不是像其他字段那样使用 faker。

?

use IlluminateSupportStr;
use FakerGenerator as Faker;

$factory->define(AppProduct::class,'tagline' => $faker->catchPhrase,'out_of_stock' => $faker->boolean,'category_id' => factory(AppCategory::class)
    ];
});

?

它知道它需要 ID,因此你不需要使用 factory()->create() 或者 factory()->create()->id 获取类别 ID。

?

现在,当你运行创建产品的测试时,它知道该产品应该属于某个类别并为你创建类别,而无需你在测试中做任何额外的操作。

?

如果对于特定的测试场景,你想创建属于某个类别的产品,则可以先定义类别,然后覆盖产品上的类别 id,使其成为你刚刚创建的类别。

?

$category = factory(AppCategory::class)->create();

$products = factory(AppProduct::class,10)->create(['category_id' => $category->id]);

?

然后就可以断言该类别有 10 个产品

?

$this->assertEquals(10,$category->fresh()->products->count());

?

希望本文能为你提供一些关于工厂测试的想法,帮你开始在测试中使用工厂,并使将来编写测试变得更加容易。

?

更多学习内容请访问:

腾讯T3-T4标准精品PHP架构师教程目录大全,只要你看完保证薪资上升一个台阶(持续更新)?zhuanlan.zhihu.com

图标

?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读