😎

phpunit-snapshot-assertionsが作るスナップショットを拡張して日本語のUnicode変換を回避する

2024/09/22に公開

はじめに

以前書いたPHPでスナップショットテストをやってみるって記事でこんなことを書いたので変換されないように対応してみました。

日本語の文字列はUnicodeエスケープされていますね。
変換されないようにするのはまた別の機会にやってみます。

環境

  • PHP 8.3.11
  • phpunit/phpunit 11.3.6
  • spatie/phpunit-snapshot-assertions 5.1.6

なぜ日本語になるのかを調べる

スナップショットのjsonファイルの中身をどこで作っているのか調べる。

https://github.com/spatie/phpunit-snapshot-assertions/blob/5.1.6/src/Drivers/JsonDriver.php#L11-L22

色々処理を追っていくとJsonDriverクラスのserializeメソッドに辿り着いた。

ここの処理でjson_encodeを使ってjson文字列を作っていることがわかる。

このjson_encodeの第2引数にJSON_UNESCAPED_UNICODEを渡すことで変換は回避できるはず。

https://www.php.net/manual/ja/json.constants.php#constant.json-unescaped-unicode

なので、このクラスを継承してserializeメソッドを拡張すれば解決だな(たぶん)

拡張する

まずはJsonDriverを拡張する。

tests/MyJsonDriver.php
<?php

declare(strict_types=1);

namespace Tests;

use Spatie\Snapshots\Drivers\JsonDriver;
use Spatie\Snapshots\Exceptions\CantBeSerialized;

class MyJsonDriver extends JsonDriver
{
    public function serialize($data): string
    {
        if (is_string($data)) {
            $data = json_decode($data);
        }

        if (is_resource($data)) {
            throw new CantBeSerialized('Resources can not be serialized to json');
        }

        return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)."\n";
    }
}

違いはjson_encodeに第2引数にJSON_UNESCAPED_UNICODEを追加だけ。

- return json_encode($data, JSON_PRETTY_PRINT)."\n";
+ return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)."\n";

つぎに拡張したJsonDriverを使うように変更しないといけない。

元々のJsonDriverはassertMatchesJsonSnapshotメソッドで使われているので、次はこのメソッドを拡張する。

https://github.com/spatie/phpunit-snapshot-assertions/blob/5.1.6/src/MatchesSnapshots.php#L92-L95

tests/MyMatchesSnapshots.php
<?php

declare(strict_types=1);

namespace Tests;

use Spatie\Snapshots\MatchesSnapshots;

trait MyMatchesSnapshots
{
    use MatchesSnapshots;

    public function assertMatchesJsonSnapshot(array|string|null|int|float|bool $actual): void
    {
        $this->assertMatchesSnapshot($actual, new MyJsonDriver());
    }
}

最後に拡張したtraitを使うようにテストクラスを変更してあげる。
テストクラスは前回の記事で使ったやつです。

tests/SnapshotTest
<?php

declare(strict_types=1);

namespace Tests;

use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
- use Spatie\Snapshots\MatchesSnapshots;

class SnapshotTest extends TestCase
{
-   use MatchesSnapshots;
+   use MyMatchesSnapshots; 

    #[Test]
    public function snapshot(): void
    {
        $this->assertMatchesJsonSnapshot(json_render());
    }
}

この状態で一度スナップショットを破棄して、再度作り直してみます。

 ./vendor/bin/phpunit tests/SnapshotTest.php
PHPUnit 11.3.6 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.11

I                                                                   1 / 1 (100%)

Time: 00:00.017, Memory: 8.00 MB

OK, but there were issues!
Tests: 1, Assertions: 3, Incomplete: 1.

作成されたスナップショットを確認してみる。

cat tests/__snapshots__/SnapshotTest__snapshot__1.json 
[
    {
        "name": "りんご",
        "price": 150,
        "stock": 10
    },
    {
        "name": "バナナ",
        "price": 200,
        "stock": 5
    },
    {
        "name": "みかん",
        "price": 120,
        "stock": 8
    }
]

日本語になっていました。

まとめ

スナップショットテストを行うだけであれば、Unicodeになっていても結果は変わらないけど実際に中身を見た時に日本語になっていた方がわかりやすいので、日本語を扱うテストでは今回の拡張は有効な手段かなって思います。

拡張する方法はこれだけではないと思うので、もし必要な機会があった時にそのプロジェクトにあった方法で拡張すると良いかと思います。

GitHubで編集を提案

Discussion