前回からの続き
前回からの続きになります。
www.tohuandkonsome.site
書いていて、どの層向けのなんのための記事なのか、という疑問が何度も頭をよぎります。
Laravelはものっそいいろんな機能があるせいか、テストコードを書くに行き着くまでにすごい時間がかかっちゃいますね。
そもそも、テストコードを書きたいという方は、Laravelのことをある程度わかった方なんじゃないかとすれば、この記事の9割9分の情報は不要なものになるなぁと思ったりします。
さらにいえば本当に必要な要素だったりといったものは、まったく書けなかったりするので、たちが悪いですね。
と、そんなことを考えているのですが最終的には自分のためだと思うのですよ!
書くことによって自分の理解がより進めばいいなと。
/threadにアクセスできることを確認する
とりあえずコードを書くときには、何かしらの仕様があるかと思うので、改めてそれを確認してみる。
ThreadTest.phpを作成
Laravelの/tests/Feature
ディレクトリ配下に、ThreadTest.php
を作成する。
artisanで作成すればpathは気にしなくていいので簡単。
ThreadTest.phpを作成
php artisan make:test ThreadTest
また、ファイル名にTestをつけないと、phpunitが検知してくれないので気をつけます。
phpunit.xmlとかでいろいろと変えれそうだけれども一旦置いておくよ!
とりあえず、こんなコードが出力されたはず。
ThreadTest.php
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ThreadTest extends TestCase
{
@return
public function testExample()
{
$this->assertTrue(true);
}
}
これについて、挙動を記載してみよう。
とりあえず、こんな感じで書いてみたよ。
<?php
class ThreadTest extends TestCase
{
@return
public function test_all_user_can_view_thread()
{
$response = $this->get('/thread');
$response->assertStatus(200) ;
}
}
これを満たすコードを書いてみる。
ThreadControllerの作成とweb.phpの修正
artisanでコントローラーを作成するよ。
ThreadControllerの作成
$ php artisan make:controller ThreadController
ThreadController.php
を適当に書いてっと、
ThreadController.php
<?php
use App\Thread;
use Illuminate\Http\Request;
class ThreadController extends Controller
{
public function index()
{
return('this is Thread');
}
}
ルーティングの定義であるweb.php
に定義してあげるっと。
web.phpの修正
<?php
Route::get('/', function () {
return view('welcome');
});
Route::get('/thread', 'ThreadController@index');
テストコードを実行する前にあれだけれども、ブラウザで/thread
にアクセスしてみると、こんな感じに表示されてるね。
Chromeのデベロッパーツールでみるとステータスコード200で返ってきてることも確認できるね!
知っている人には当たり前の話かもしれないけれども、コントローラーで適当なメッセージをreturnしても、レスポンスヘッダーをちゃんとつけて返したりするのはすごいなぁと改めて思ったりしました。
テストコードを実行してみる
それではテストコードを実行してみよう。
テストコードの実行
$ phpunit
PHPUnit 6.4.4 by Sebastian Bergmann and contributors.
.... 4 / 4 (100%)
Time: 1.19 seconds, Memory: 10.00MB
OK (4 tests, 4 assertions)
「OK」っていってるので大丈夫そうですね!
4testsとかになってるのは、デフォルトで用意されているExampleTestがカウントされているみたいですね。
Threadが見えることの確認
さきほどは/threadにアクセスするとステータスコードが200だぜ!っていうテストをクリアすることができました。
次はもう一歩先に進んで、/threadにアクセスすると、Thread(トピック)の一覧が見えるってことを確認していきましょう。
テストコードを書いてみます。
TestThread.php
<?php
@return
public function test_all_user_can_access_thread()
{
$response = $this->get('/thread');
$response->assertStatus(200) ;
}
@return
public function test_all_user_can_view_thread()
{
$response = $this->get('/thread');
$response->assertSee('this is Thread');
}
threadの一覧が見えること、というテストコードを作成しました。
メソッド名を変更しているので注意してください。
新しくaseertSee
というメソッドがでてきましたね。
assertSee
assertSeeが何者なのかということなのですが、Laravelのソースを見てみると、以下のようにPHPUnitのassertContains
の機能をラッパーしたものであることがわかりますね。
細かいことはさておき、クライアントに返すレスポンスの中に、引数で与えられた$value
が存在するかどうかを確認してくれる、というものでしょうか。
<?php
@param
@return
public function assertSee($value)
{
PHPUnit::assertContains($value, $this->getContent());
return $this;
}
とりあえず、今の状態でphpunit
を実行してみましょう。
$ phpunit
PHPUnit 6.4.4 by Sebastian Bergmann and contributors.
..... 5 / 5 (100%)
Time: 1.21 seconds, Memory: 10.00MB
OK (5 tests, 5 assertions)
問題なく通りますね。
これは、ThreadController@index
で、文字列「this is Thread」をreturnしていて、それがレスポンスとしてクライアントに返っているからですね。
Chromeでレスポンスを確認してみると、内容が確認できます。
テストコード修正
さて、さきほどのテストコードは、文字列「this is thread」が確認できただけなので、Threadの内容が見えること、というように修正していく必要があります。
テストコードのイメージはこんな感じでしょうか。
<?php
@return
public function test_all_user_can_view_thread()
{
$thread = ???
$response = $this->get('/thread');
$response->assertSee($thread->body);
}
ここで問題となるのは、最初にでてくる$thread
を作成するコードです。
factory(ファクトリ)を使う
Laravelで用意されているテストデータを作成できるツールを使っていきます。
と、テストデータを作成する前に、データを定義する(表現が怪しい)をモデルだったりを作っていきましょう。
Threadモデルの作成
Threadを表現する、Threadモデルを作成します。
マイグレーションファイルも一緒に作っちゃいましょう。
モデルとマイグレーションファイルの作成
$ php artisan make:model Thread -m
こんな感じの空っぽのモデルと、
Thread.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Thread extends Model
{
}
/database/migrations配下に以下のファイルができたかな。
作成した日付_create_threads_table.php(抜粋)
<?php
class CreateThreadsTable extends Migration
{
@return
public function up()
{
Schema::create('threads', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
});
}
Threadマイグレーションファイルの修正
できたばかりのマイグレーションファイルに手を加えていきます。
Threadには、見出しであるtitle
と内容であるbody
を足してあげます。
また、誰が作成したかがわかるように、Threadに作ったユーザーのidであるuser_id
を付加してあげましょう。
作成した日付_create_threads_table.php(抜粋)
<?php
class CreateThreadsTable extends Migration
{
@return
public function up()
{
Schema::create('threads', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
}
指定してできるカラムタイプは結構適当だよ!
カラムタイプの詳細は公式をみよう。
データベース:マイグレーション 5.5 Laravel
マイグレーションファイルを修正したら、マイグレーションを実行してテーブルを作成しよう。
マイグレーションを実行
php artisan migrate
Threadテーブル以外にも、デフォルトでマイグレーション用意されている、Userテーブルだったりが作成されるはず。
データベースのインストールだったり、.envの環境変えてねえよ!っていう場合は
速攻でググるなり導入するなりしよう!
factoryを書いていこう
/database/factories
を覗いてみると、UserFactory.php
というものがいるかと思います。
UserFactory.php(抜粋)
<?php
$factory->define(App\User::class, function (Faker $faker) {
static $password;
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
];
});
これはなんぞ、という感じなのですが、Userテーブルにテストデータを作成するためのコードになります。
試しに実行してみましょう。
tinkerの起動
$ php artisan tinker
Psy Shell v0.8.15 (PHP 7.1.9-1+ubuntu16.04.1+deb.sury.org+1 — cli) by Justin Hileman
>>>
さて、でてきました。`tinker'です。
正直なんなのかよくわかってないです!
公式をみると
全てのLaravelアプリケーションには、PsySHパッケージによるREPLである、Tinkerが含まれています。
とあり、`PsySH'だったり'REPL'ってなんぞって感じになります。
素敵な記事がこちらにありました。
qiita.com
自分の浅い理解では、PythonとかはCLIでpythonを起動すると、実行しながらコードかけるあの感じと考えることにしました。
とはいえ、tinkerはphpを対話型で書ける以上に、Laravelの機能を含んでいる何かなのかなぁと思うことにして、次に進みます。
話がそれてしまいましたが、tinkerでさきほどの`Userfactory.php'のコードを実行してみましょう。
コードを試す
$ php artisan tinker
Psy Shell v0.8.15 (PHP 7.1.9-1+ubuntu16.04.1+deb.sury.org+1 — cli) by Justin Hileman
>>> factory('App\User')->create()
=> App\User {
name: "Bernardo Abbott",
email: "vada97@example.com",
updated_at: "2017-11-25 06:07:48",
created_at: "2017-11-25 06:07:48",
id: 1,
}
>>>
おお、となりましたか?
自分はなりました。
factory()という謎の関数なのかメソッドなのかわからないものにクラス名を渡して、create()をしてあげると、名前やらemailアドレスやらにそれっぽい値が入ってデータが作成されます。
また、データベースを確認してみると、作成されたデータが保存されていることが確認できるかと思います。
表面しかわかりませんが、とりあえずこんな感じでデータをつくれるということですね。
Thread用のデータを書いていきましょう。
本来であればThreadFactory.phpなるものをつくったほうがよいのかもしれませんが、UserFactory.phpに追記する形で書いてみました。
UserFactory.php(抜粋)
$factory->define(App\Thread::class, function (Faker $faker) {
return [
'user_id' => 1,
'title' => "ピンキーのかわいさについて",
'body' => "動いているところがいいよね"
];
});
これで、さきほどの同じ様にtinkerで実行してみましょう。
実行する際に、tinkerを起動しっぱなしだと、UserFacotry.php
の修正が反映されないかもなので、一旦exitして、もっかい起動してあげてね。
コードを試す
>>> factory('App\Thread')->create()
=> App\Thread {
user_id: 1,
title: "ピンキーのかわいさについて",
body: "動いているところがいいよね",
updated_at: "2017-11-25 06:17:15",
created_at: "2017-11-25 06:17:15",
id: 1,
}
こんな感じでデータが作成されましたね。
さて、データが作成されてようやく次へというところなんですが、このままだとまったく同じテストデータしか作成されません。
titleやbodyの内容は今のままでも全く問題ないのですが、user_idが固定というのは、ちょっといただけないかもしれません。
というのも、user_idはこのThreadデータを作成したユーザーが紐づいていてほしいからです。
なのでこれを修正していきます。
というところで次回に続きたいと思います。