spatie/tabular-assertions

使用 Pest 或 PHPUnit 编写表格断言

1.0.0 2024-01-08 13:37 UTC

This package is auto-updated.

Last update: 2024-09-15 18:34:36 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

表格断言允许您以类似 Markdown 表格的格式描述数据,并将其与实际数据进行比较。这对于比较像财务数据或时间序列这样的大型有序数据集非常有用。

使用 Pest

test('it compares a table', function () {
    $order = Order::factory()
        ->addItem('Pen', 2)
        ->addItem('Paper', 1)
        ->addItem('Pencil', 5)
        ->create();

    expect($order->items)->toMatchTable('
        | #id | #order_id | name   | quantity |
        |  #1 |        #1 | Pen    |        2 |
        |  #2 |        #1 | Paper  |        1 |
        |  #3 |        #1 | Pencil |        5 |
    ');
});

使用 PHPUnit

use PHPUnit\Framework\TestCase;
use Spatie\TabularAssertions\PHPUnit\TabularAssertions;

class PHPUnitTest extends TestCase
{
    use TabularAssertions;

    public function test_it_contains_users(): void
    {
        $order = Order::factory()
            ->addItem('Pen', 2)
            ->addItem('Paper', 1)
            ->addItem('Pencil', 5)
            ->create();

        $this->assertMatchesTable('
            | #id | #order_id | name   | quantity |
            |  #1 |        #1 | Pen    |        2 |
            |  #2 |        #1 | Paper  |        1 |
            |  #3 |        #1 | Pencil |        5 |
        ', $order->items);
    }
}

支持我们

我们投入了大量资源来创建一流的开放式源代码包。您可以通过购买我们的付费产品之一来支持我们。

我们非常感谢您从家乡给我们寄来明信片,并说明您正在使用我们的哪个包。您可以在我们的联系页面找到我们的地址。我们将所有收到的明信片发布在我们的虚拟明信片墙上

安装

您可以通过 composer 安装此包

composer require spatie/tabular-assertions

为什么选择表格断言?

表格断言相对于其他测试策略有两个主要优点:期望优化了可读性,失败的断言可以一次性显示多个错误。

1. 您可以手动编写包含大量数据且优化了可读性的期望。 基于文本的表格紧凑,允许您在两个维度上比较数据。

另一种选择是编写多个断言。

expect($items[0]['order_id'])->toBe($order->id);
expect($items[0]['name'])->toBeDate('Pen');
expect($items[0]['quantity'])->toBe(2);

expect($items[1]['order_id'])->toBe($order->id);
expect($items[1]['name'])->toBeDate('Paper');
expect($items[1]['quantity'])->toBe(1);

// …

期望要求您逐个断言每个属性。这使得您很难一目了然地看到所有日期,并且总体上可读性较差。

关联数组需要大量的标签重复。

expect($items[0])->toBe([
    'order_id' => $order->id,
    'name' => 'Pen',
    'quantity' => 2,
]);

expect($items[1])->toBe([
    'order_id' => $order->id,
    'date' => 'Paper',
    'quantity' => 1,
]);

// …

没有键的数组无法正确对齐(手动维护的空格会被代码风格修复器删除)。当断言具有不同长度的多列时,这会变得不清楚。

expect($items)->toBe([
    [$order->id, 'Pen', 2],
    [$order->id, 'Paper', 1],
    // …
]);

使用表格断言,我们可以获得数据的紧凑、可读的概述,并且因为它存储在单个字符串中,所以代码风格修复器不会重新格式化它。

expect($items)->toMatchTable('
    | #id | #order_id | name   | quantity |
    |  #1 |        #1 | Pen    |        2 |
    |  #2 |        #1 | Paper  |        1 |
    |  #3 |        #1 | Pencil |        5 |
');

2. 可以显示多个问题的错误。 使用单独的期望,测试在第一个失败的断言处失败,这意味着您没有完整的画面(小问题 vs. 一切都坏了)

如果您将两个数据集序列化为表格,当您使用 assertEquals 时,您将得到像 PhpStorm 输出一样的视觉差异。

在这个断言中,您可以一眼看出一个值是错误的,还有一个行缺失。使用单独的断言,您只能看到测试运行器遇到的第一个错误。

CleanShot 2023-02-09 at 14 48 38@2x

这种测试风格在您有大量数据需要断言时表现得尤为出色。这个例子有 9 行和 9 列,这意味着我们在保持可读性的同时比较了 81 个数据点。

expect($order->logs)->toLookLike("
    | type        | reason   | #product_id | #tax_id | #shipping_id | #payment_id | price | paid  | refunded |
    | product     | created  |       #1    |         |              |             | 80_00 | 80_00 |     0_00 |
    | tax         | created  |       #1    |      #1 |              |             |  5_00 |  5_00 |     0_00 |
    | tax         | created  |       #1    |      #2 |              |             | 10_00 | 10_00 |     0_00 |
    | shipping    | created  |       #1    |         |           #1 |             |  5_00 |  5_00 |     0_00 |
    | product     | paid     |       #1    |         |              |          #1 |  0_00 |  0_00 |     2_00 |
    | tax         | paid     |       #1    |      #1 |              |          #1 |  0_00 |  0_00 |     0_00 |
    | tax         | paid     |       #1    |      #2 |              |          #1 |  0_00 |  0_00 |     0_00 |
    | shipping    | paid     |       #1    |         |           #1 |          #1 |  0_00 |  0_00 |     0_00 |
");

用法

基本用法:Pest

使用 Pest,插件将自动加载并可用。使用自定义的 toMatchTable() 期望来比较表格中的数据。

基本用法:PHPUnit

使用 PHPUnit,将 Spatie\TabularAssertions\PHPUnit\TabularAssertions 特性添加到您想使用表格断言的测试中。使用 $this->assertMatchesTable() 来比较表格中的数据。

动态值

有时,您可能想要比较数据,但实际上并不需要比较确切值。例如,您想要断言每个人都在同一个团队中,但不知道团队ID,因为每次运行时数据都是随机生成的。可以通过在列名前加一个 # 来标记列名为“动态”。动态列将使用占位符替换值。占位符对于列中的值是唯一的。因此,具有ID 123 的团队将始终渲染为 #1,另一个ID为 456 的团队将使用 #2 等。

例如,Sebastian和Freek在Spatie团队,该团队有一个随机ID,而Christoph在Laravel团队,也有另一个随机ID。

| name      | #team_id |
| Sebastian |       #1 |
| Freek     |       #1 |
| Christoph |       #2 |

自定义断言

表格断言会将实际值转换为字符串。我们经常处理比可字符串化的数据更复杂的数据,在这种情况下,创建一个自定义断言方法来准备数据是值得的。

考虑以下示例,其中有一个 User 模型,它具有 idnamedate_of_birth,这些将被转换为 Carbon 对象。

expect(User::all())->toMatchTable('
    | id | name       |       date_of_birth |
    |  1 | Sebastian  | 1992-02-01 00:00:00 |
');

由于 Carbon 对象在字符串化时会自动附加秒,因此我们的表格变得嘈杂。相反,我们将创建一个自定义的 toMatchUsers 断言来在我们断言之前准备我们的数据。

expect()->extend('toMatchUsers', function (string $expected) {
    $users = $this->value->map(function (User $user) {
        return [
            'id' => $user->id,
            'name' => $user->name,
            'date_of_birth' => $user->date_of_birth->format('Y-m-d'),
        ];
    });

    expect($users)->toBe($expected);
});
expect(User::all())->toMatchTable('
    | id | name       | date_of_birth |
    |  1 | Sebastian  |    1992-02-01 |
');

在PHPUnit中,这将是一个自定义断言方法。

class UserTest extends TestCase
{
    use TabularAssertions;

    private function assertMatchesUsers(string $expected, Collection $users): void
    {
        $users = $users->map(function (User $user) {
            return [
                'id' => $user->id,
                'name' => $user->name,
                'date_of_birth' => $user->date_of_birth->format('Y-m-d'),
            ];
        });

        $this->assertMatchesTable($expected, $users);
    }
}

这也可以用于在断言之前进行任何数据转换或截断。另一个例子:first_namelast_name 可能是数据库中的单独列,但在断言中可以合并它们,以减少表格中的不必要的空白。

expect(User::all())->toMatchTable('
    | id | name                | date_of_birth |
    |  1 | Sebastian De Deyne  |    1992-02-01 |
');
expect()->extend('toMatchUsers', function (string $expected) {
    $users = $this->value->map(function (User $user) {
        return [
            'id' => $user->id,
            'name' => $user->first_name . ' ' . $user->last_name,
            'date_of_birth' => $user->date_of_birth->format('Y-m-d'),
        ];
    });

    expect($users)->toBe($expected);
});

灵感与替代方案

这个想法受到了Jest的启发,Jest允许您使用表格作为数据提供者

快照测试也与这一点密切相关。但快照并不总是针对可读性进行优化,它们存储在单独的文件中(不是与测试一起),并且很难手动编写(没有TDD)。

测试

使用Pest编写测试。您可以使用Pest的CLI或运行 composer test 来运行测试套件。

composer test

除了测试之外,PhpStan还会进行静态代码分析。使用 composer analyse 来运行PhpStan。

composer analyse

变更日志

有关最近更改的更多信息,请参阅变更日志

贡献

有关详细信息,请参阅贡献指南

安全漏洞

有关如何报告安全漏洞的详细信息,请参阅我们的安全策略

鸣谢

许可

MIT许可(MIT)。有关更多信息,请参阅许可文件