豆腐とコンソメ

豆腐とコンソメ

もろもろのプログラム勉強記録

Laravelで始めるTDD開発(2):テストデータをつくる

前回からの続き

前回は、Threadのテストデータを作成する際に、固定のデータしかつくれないよ、というところで終わってました。

www.tohuandkonsome.site


UserFactory.phpを修正する

前回のUserFactory.php

<?php
$factory->define(App\Thread::class, function (Faker $faker) {

    return [
        'user_id' => 1,
        'title' => "ピンキーのかわいさについて",
        'body' => "動いているところがいいよね" 
    ];
});

まず、Threadに持たせるuser_idは、Userデータが存在するuser_idを設定するようにします。

これだけ聞くと、自分だったら以下のようにuser_idの部分にデータベースからUserの情報をとってくることをしてたかもしれません。
\App\User::find(1)->idってなんぞって思われ方は無視しても特に問題はないです!

言いたかったことは、存在するUserのidをThreadのuser_idに設定したいのであれば、存在するUserの情報をデータベースからとってきれ、それを設定する、ということをするという方法をとってただろうなぁということです。

UserFactory.php

<?php
$factory->define(App\Thread::class, function (Faker $faker) {

    return [
        'user_id' => \App\User::find(1)->id,
        'title' => "ピンキーのかわいさについて",
        'body' => "動いているところがいいよね" 
    ];
});

一方、頼りにしているLaracastでは、こうしていました。

UserFactory.php(抜粋)

<?php
$factory->define(App\Thread::class, function (Faker $faker) {

    return [
        'user_id' => factory('App\User')->create()->id,
        'title' => "ピンキーのかわいさについて",
        'body' => "動いているところがいいよね" 
    ];
});

存在しているUserのuser_idをセットするという発想ではなく、Threadのテストデータ作成の際に、Userをつくっちゃって、そのidを設定すればいいじゃないという発想ですね。

すごい!
(ただ、1対多のリレーションのデータを作成したいときにはどうするんだろう、とふと思いました)

さて、これで作成されるThreadのテストデータには、必ず対応するUserがいることになります。

せっかくなのでtitlebodyもランダムな文字列が設定されるようにしちゃいましょう(残念ですが)。

UserFactory.php(抜粋)

<?php
$factory->define(App\Thread::class, function (Faker $faker) {

    return [
        'user_id' => factory('App\User')->create()->id,
        'title' => $faker->sentence,
        'body' =>  $faker->paragraph 
    ];
});

Fakerというクラスのメソッドでいい感じにデータを作成することができるみたいです。
こちらのFakerなんですが、githubにどんなメソッドがあって、どんなデータが作成されるかが書いてあります。

github.com

日本語用のFakerもあったりするみたいなのですが、こちらは試せてません。


話を戻してテストコード

回を跨いでしまったので、何をやってたか忘れかけてましたが、テストコードです。

前回はこんな感じで終わってましたね。

ThreadTest.php

<?php

    /**
     * すべてのユーザーは、/threadにアクセスすると、Threadの一覧が見えること
     *
     * @return void
     */
    public function test_all_user_can_view_thread()
    {
        //Threadがあって
        $thread = ???
        
        //Threadの一覧を表示するURLにアクセスすると
        $response = $this->get('/thread');
        
        //Threadの内容が見えるんだよ
        $response->assertSee($thread->body);

    }

このThreadTest.phpを以下のように修正します。

ThreadTest.php

<?php

    /**
     * すべてのユーザーは、/threadにアクセスすると、Threadの一覧が見えること
     *
     * @return void
     */
    public function test_all_user_can_view_thread()
    {
        //Threadがあって
        $thread = factory('App\Thread')->create();

        //Threadの一覧を表示するURLにアクセスすると
        $response = $this->get('/thread');
        
        //Threadの内容が見えるんだよ
        $response->assertSee($thread->body);

    }

くどいようですが、assertSeeで$thread->bodyの文字列がレスポンスの中にあるかを確認しています。

さて、このテストコードをクリアするために、実装を書いていきましょう。


実装を書く

ここでは、/threadにアクセスしにきたときの制御を書くThreadController.phpと画面に描画されるHTMLの素となるindex.blade.phpを書いていきます。


コントローラーの修正

コントローラーはこんな感じになります。

ThreadController.php

<?php

namespace App\Http\Controllers;

use App\Thread;
use Illuminate\Http\Request;

class ThreadController extends Controller
{
    public function index(Thread $thread)
    {
        $threads = $thread->all();
        return view('thread.index', compact('threads'));
    }

}

Threadクラスはメソッドの中でnewして、インスタンス化してももちろんいいはず。

ただ、Laravelは引数にクラスを書いてあげると、それをインスタンス化して渡してくれるという機能を備えているので、ここでは引数に指定しているよ。

この引数に指定してインスタンス化くれることを「依存性の注入」みたいな表現で書かれていたりする。(間違ってたらごめんよ!)

依存性の注入を紐解けば、DIコンテナみたいな話がでてくるんだけど、このへんんお有用性があんまりわかってないので、しっくりきたらまた書こうと思うんだ。
(どうもクラス間の依存性をなくすことでテストしやすいコードが〜みたいな話なので、今回の学習を通して理解できれば幸せ)


index.blade.phpの修正

/resources/views配下にthreadディレクトリを作成して、index.blade.phpを作成するよ。

index.blade.php

<h1>This is Thread!</h1>

<ul>
    @foreach($threads as $thread)
        <li>{{ $thread->title }}</li>
        <li>{{ $thread->body }}</li>
        <hr/>
    @endforeach
</ul>

ここでは最小限のコードにするよ。


テストコードの実行

さあ、これでテストコードを実行してみよう。

テストコードの実行

$ phpunit
PHPUnit 6.4.4 by Sebastian Bergmann and contributors.

.....                                                               5 / 5 (100%)

Time: 1.47 seconds, Memory: 14.00MB

OK (5 tests, 5 assertions)

無事、通りましたね!

試しにブラウザで/threadにアクセスしてみると 、こんな画面が表示されました。

f:id:konoemario:20171127221851p:plain
/threadにアクセスした場合

せっかくなので、テストコードについても、thread->bodyだけではなく、`thread->title'も追加しておきました。

<?php
    /**
     * すべてのユーザーは、/threadにアクセスすると、Threadの一覧が見えること
     *
     * @return void
     */
    public function test_all_user_can_view_thread()
    {
        //Threadがあって
        $thread = factory('App\Thread')->create();

        //Threadの一覧を表示するURLにアクセスすると
        $response = $this->get('/thread');
        
        //Threadの内容が見えるんだよ
        $response->assertSee($thread->body)
                 ->assertSee($thread->title);
    }

ここまでのソース

github.com