質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

PHPUnit

PHPUnitは、PHP向けのユニット・テスト向けフレームワークで、手動では手間のかかるテスト作業を自動化し、繰り返し実行することが可能です。

デバッグ

デバッグはプログラムのバグや欠陥を検知し、開発中のバグを取り除く為のプロセスを指します。

ユニットテスト

ユニットテストは、システムのテスト手法の一つで、個々のモジュールを対象としたテストの事を指します。対象のモジュールが要求や性能を満たしているか確認する為に実行します。

Q&A

解決済

1回答

1895閲覧

laravelのテストコードをデバッグした際にDBデータが反映されない【RefreshDatabase】

koiking510

総合スコア1

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

PHPUnit

PHPUnitは、PHP向けのユニット・テスト向けフレームワークで、手動では手間のかかるテスト作業を自動化し、繰り返し実行することが可能です。

デバッグ

デバッグはプログラムのバグや欠陥を検知し、開発中のバグを取り除く為のプロセスを指します。

ユニットテスト

ユニットテストは、システムのテスト手法の一つで、個々のモジュールを対象としたテストの事を指します。対象のモジュールが要求や性能を満たしているか確認する為に実行します。

0グッド

0クリップ

投稿2022/12/29 16:48

編集2022/12/30 11:28

前提

laravelでテストコード(PHPUnit)を書いていますが、
処理の中でDBのテーブルにレコードをINSERTした後に、
デバッグで一時停止した状態でコマンドラインからテーブルをSELECTすると、
結果が反映されていない状態(レコード0件)で結果が返ってきます。(想定としてはSELECTの結果レコードが返ってくるはず)

use RefreshDatabase;をコメントアウトすると、想定通りレコードが返ってくるので、
RefreshDatabaseが関係していると思ったのですが、どうしても想定通りになりませんでした。

実現したいこと

デバッグで一時停止した状態でSELECTしたら、想定通りレコードが返ってくるようにしたいです。
または仕様として、レコードが返ってこない仕様なのであればそれを知りたいです。

意図

テストコード書くのは初心者です。
テストコードの中で、seeder等でテストデータを入れたりしたいので、
デバッグで一時停止して、DBの値を見ながらテストコードを書きたいと思った次第です。
(そもそもテストコードをデバッグするということ自体が間違っているのでしょうか・・?)

環境

MacBookAir macOS Monterey 12.4 Intel
Docker Desktop(ローカル開発・検証)
PHP 8.1.12
Laravel Framework 8.75
PHPUnit 9.5.10
Xdebug 3.2.0

検証用のプロジェクトリポジトリ(GitHub)

https://github.com/corock510/Experiment

該当のソースコード

UserTest.php

1<?php 2 3namespace Tests\Feature; 4 5use Illuminate\Foundation\Testing\RefreshDatabase; 6use Illuminate\Support\Facades\Log; 7use Tests\TestCase; 8 9use Illuminate\Support\Facades\DB; 10 11class UserTest extends TestCase 12{ 13 use RefreshDatabase; 14 15 /** 16 * A basic feature test example. 17 * 18 * @return void 19 */ 20 public function test_create_user() 21 { 22 //クエリビルダを用いて、usersテーブルに2件レコード追加(本来ここはテストコードではなくテスト対象のクラスのメソッドに書きますが、便宜的にここにINSERT処理を書いています。) 23 DB::table('users')->insert([ 24 ['name' => 'A', 'email' => '1@test.com', 'password' => 'aaa'], 25 ['name' => 'B', 'email' => '2@test.com', 'password' => 'aaa'] 26 ]); 27 28 //検証用 ブレークポイント usersテーブルにselect文流して$getValに代入 29 $getVal = DB::table('users')->select('name')->get(); 30 31 //検証用 ログ(src/storage/logs/laravel.log)に$getValの値を書き込み 32 Log::info($getVal); 33 34 //usersテーブルの件数が2件であればテストOK 35 $this->assertDatabaseCount(table: 'users', count: 2); 36 } 37}

詳細

上記のUserTest.phpでは、usersテーブルにレコードを2件INSERTし、その件数が2件であることをテストしています。
INSERT処理の直後(29行目)にブレークポイントを張ってデバッグで一時停止した状態で、コマンドライン上からMySQLに接続し、
usersテーブルにSELECT文を流すと、結果は2件のはずが、0件(Empty set)で返ってきます。
その後、UserTest.phpをステップ実行すると、想定通り2件取得できています。

冒頭でも書きましたが、13行目のuse RefreshDatabase;をコメントアウトすると、④で想定通り2件返ってきます。

検証手順

①拡張機能のxDebugをインストール済の状態で【cmd + shift + D】【F5】でxDebugを実行
②UserTest.phpの29行目selectの処理にブレークポイントを設定(Error Exception Uncaught Exceptionのチェックを外す)
③下記記載(1)の方法で、UserTest実行(②のブレークポイントで一時停止する)
④下記記載(2)の方法で、コマンドライン上でMySQLに接続して、usersテーブルにSELECT文を流す(結果は2件のはずが、0件(Empty set)で返ってくる)
⑤UserTest.phpの処理をステップ実行する(想定通り2件取得できている)

(1)UserTest実行
$ docker compose exec php bash
# ./vendor/bin/phpunit tests/Feature/UserTest.php

(2)DB接続、usersテーブルSELECT文発行
$ docker compose exec db mysql -u root -p
password
> use database;
> select name from users;


何卒、よろしくお願いいたしますm(_ _)m

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yuma.inaura

2022/12/30 01:13

自分のMac環境でも試しましたが普通に成功しますね むしろ use RefreshDatabase を外すと二回目以降の実行で 重複レコード登録で失敗しました
yuma.inaura

2022/12/30 01:16

https://github.com/corock510/Experiment のコードで docker から実行しましたがこちらもテストが成功しました root@bedaeb24c0f5:/var/www/html# ./vendor/bin/phpunit tests/Feature/UserTest.php Deprecated: PHP Startup: Use of mbstring.internal_encoding is deprecated in Unknown on line 0 PHPUnit 9.5.27 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 00:02.053, Memory: 24.00 MB OK (1 test, 1 assertion)
koiking510

2022/12/30 02:28

検証ありがとうございます。 はい、テストは私の方でも成功します。 「DBにレコードが2件存在することのテスト」は成功するのに、 デバッグで一時停止して、コマンドラインでSELECTした時に0件で返ってくるのは何故か? という質問でした。
guest

回答1

0

ベストアンサー

テストでのDBの扱い方はいくつか方法がある。

  1. トランザクション内で実行。RefreshDatabaseはこれ。
  2. 別データベースで実行。sailはこれ。
  3. インメモリSQLiteを使用。

前提として必須な常識は「テストで既存のデータベースを変更されたら困る」
これが分かってないと何も理解できない。

1 RefreshDatabase

トランザクション内なので既存のデータベースには影響を与えない。つまりテストの途中で中を見ても何もない。質問への回答はここだけで終わり。「DBのテストにはRefreshDatabaseを使う。テスト中に中を見るような意味のないことをしない」

RefreshDatabaseなしで他の方法も使ってないなら既存のデータベースを変更している。テストの途中でも変更が反映されるけどそれはつまり既存のデータベースが壊れてるのでやってはいけないこと。

2 別データベース

sailではphpunit.xmlが書き換えられて
DB_DATABASE=testingという別のデータベースが使われるので既存のデータベースへの影響はない。

3 インメモリSQLite

コメントアウトされてるけどLaravelのデフォルトのphpunit.xmlはインメモリSQLiteをすぐ使えるように用意されている。

<!-- <env name="DB_CONNECTION" value="sqlite"/> --> <!-- <env name="DB_DATABASE" value=":memory:"/> -->

全部既存のデータベースを壊さないための方法。

投稿2022/12/29 23:48

kawax

総合スコア10377

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

koiking510

2022/12/30 02:25

ご回答ありがとうございます。 >前提「テストで既存のデータベースを変更されたら困る」 →こちらは理解しました。 >トランザクション内なので既存のデータベースには影響を与えない。つまりテストの途中で中を見ても何もない。質問への回答はここだけで終わり。 →なるほど、おそらく理解できました。  RefreshDatabaseを使用したテストは、トランザクションが開始された状態でテスト実行され、テスト中は未コミットの状態になっているため、コマンドライン上からDBを見ても反映されていない というイメージでしょうか。 >テスト中に中を見るような意味のないことをしない →やはりそういうことなのですね。これが聞けて良かったです。 他の方法もご提示いただきありがとうございます。参考にさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問