4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel 5.8 の assertDatabaseHas を使用したさい、日本語(unicode)がエスケープされる問題の修正方法

Last updated at Posted at 2019-09-29

問題

assertDatabaseHasでテストが失敗したとき
$this->call('PATCH', '/api/users/1', ['name' => 'ほげほほげ']);
$this->assertDatabaseHas('users', ['name' => 'ふがふが']);
データベース内のマルチバイトが正しく表示されない
# There was 1 failure:
# 
# 1) Tests\Feature\UsersControllerTest::testUsersUpdate
# Failed asserting that a row in the table [users] matches the attributes {
#     "title": "\u3075\u304c\u3075\u304c"
# }.
# 
# Found: [
#     {
#         "id": 1,
#         "title": "\u307b\u3052\u307b\u307b\u3052",
#         "created_at": "2019-09-29 09:33:59",
#         "updated_at": "2019-09-29 09:33:59"
#     }
# ].

結論

文字化けの原因は class InteractsWithDatabase 内で使用している json_encode の第2引数が JSON_PRETTY_PRINT のみになっているため。

これは、./tests/TestCase.phpassertDatabaseHas でオーバーライドして引数を修正できる

./tests/TestCase.php
<?php

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;

    /**
     * @see github.com/laravel/framework/blob/5.8/src/Illuminate/Foundation/Testing/Concerns/InteractsWithDatabase.php#L21
     */
    protected function assertDatabaseHas($table, array $data, $connection = null)
    {
        $this->assertThat(
            $table,
            new HasInDatabaseMb($this->getConnection($connection), $data)
        );

        return $this;
    }
}

class BaseTestCase > trait InteractsWithDatabase > class HasInDatabase のような依存で、実際の出力整形はHasInDatabaseクラスのメソッドが行っているため、json_encodeを使用しているメソッドを上書きして新しいクラス ./tests/HasInDatabaseMb.php とする。

./tests/HasInDatabaseMb.php
<?php

namespace Tests;

use Illuminate\Foundation\Testing\Constraints\HasInDatabase;

class HasInDatabaseMb extends HasInDatabase
{
    /**
     * @see github.com/laravel/framework/blob/5.8/src/Illuminate/Foundation/Testing/Constraints/HasInDatabase.php#L66
     */
    protected function getAdditionalInfo($table)
    {
        $results = $this->database->table($table)->get();

        if ($results->isEmpty()) {
            return 'The table is empty';
        }

        $description = 'Found: '.json_encode($results->take($this->show), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

        if ($results->count() > $this->show) {
            $description .= sprintf(' and %s others', $results->count() - $this->show);
        }

        return $description;
    }

    /**
     * @see github.com/laravel/framework/blob/5.8/src/Illuminate/Foundation/Testing/Constraints/HasInDatabase.php#L84
     */
    public function toString($options = 0): string
    {
        return json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    }
}

上記はオリジナルのソースコードの json_encode の第2引数を

  • JSON_PRETTY_PRINT

から↓

  • JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE

に変更を行い、それ以外は変更していない。
以上のようにして assertDatabaseHas メソッドをオーバーライドすれば、テスト失敗時に日本語が表示されるようになる。

# Time: 1.69 seconds, Memory: 24.00 MB
# 
# There was 1 failure:
# 
# 1) Tests\Feature\UsersControllerTest::testUsersUpdate
# Failed asserting that a row in the table [users] matches the attributes {
#     "title": "ふがふが"
# }.
# 
# Found: [
#     {
#         "id": 1,
#         "title": "ほげほほげ",
#         "created_at": "2019-09-29 09:50:00",
#         "updated_at": "2019-09-29 09:50:00"
#     }
# ].
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?