10
5

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 3 years have passed since last update.

【Laravel】PHPUnitでの単体テストについて簡単にまとめて、実装していく

Last updated at Posted at 2021-08-30

目次

1.単体テストとは?
2.単体テストを書くメリット
3.単体テストの作成
4.参考

1. 単体テストとは?

関数や、メソッド単位で動作確認を行う。

2. 単体テストを書くメリット/デメリット

メリット

  • モジュールが結合される前にテストができるため、問題の原因特定がしやすい
  • コードの作成と同時にテストコードが書いていくため、テストケースが資産として残っている。
    つまり、後々の改修がしやすい
  • PHPUnitを使うことで自動化できる→コマンド一つで動作確認が可能(改修時の確認においても)

デメリット

  • 開発者の開発負担が高くなる

3. 単体テストの作成

FeatureとUnit

どちらもtestsディレクトリはいかに存在するディレクトリです。
どちらのディレクトリでもテストを記載できるのですが、どのように使い分けるべきかまとめました。

ディレクトリ 使い分けについての説明
Feature 1つのHTTPリクエストの動作テスト / UnitよりもTest範囲が広い
Unit 作成したクラスそれぞれに対応するテストクラス作成(Service、Model、Middlewareなど) / 1つ1つのメソッドなどの動作検証 / (ControllerはFeatureに。)

以下参考記事です。

実装していく

と、まとめてみたものの実際に実装しないとよく分からないので、

以前、実装したコードを元にどんどんテストしていきます。

- 意識する事 -
Feature / Unitを使い分けて書く
メソッド単位〜HTTPリクエストまで幅広くテストコードをどんどん書いていく
// Featureディレクトリにテストを生成する
$ php artisan make:test Post/ToPostTest

// Unitディレクトリにテストを生成する
$ php artisan make:test Post/ToPostTest --unit

テストを書いていきます。

●<HTTPリクエストテスト>

基本的な機能テスト

test.php
<?php

namespace Tests\Feature\Post;

use Tests\TestCase;

class ToPostTest extends TestCase
{
    public function testGetPage()
    {
        $response = $this->get('/post/topost');
        $response->assertStatus(302);
    }
}

●<データ検索:存在チェック>

存在するもの、しないもの、どちらも検索をかけてチェックしています。

test.php
<?php

namespace Tests\Feature\Post;

use Tests\TestCase;

class ToPostTest extends TestCase
{
    /**
     * 投稿用のお風呂の検索
     *
     * @return void
     */
    public function testSearchBathName()
    {
        // 都道府県検索
        $place = Bath::where('place', '東京都')->first();
        $this->assertNotNull($place); // Nullで無ければtrue
        $place = Bath::where('place', '韓国')->first();
        $this->assertNull($place);
        $place = Bath::where('place', 'トウキョウ')->first();
        $this->assertNull($place);
        $place = Bath::where('place', 'tokyo')->first();
        $this->assertNull($place);
        $place = Bath::where('place', '東京')->first();
        $this->assertNull($place);

        // キーワード検索:あいまい検索
        $keyword1 = Bath::where('name', 'like', "%ああ%")->first(); // nameカラムに、「あ」があることの確認
        $this->assertNotNull($keyword1);
        $keyword2 = Bath::where('name', 'like', "%a%")->first(); // nameカラムに、「a」があることの確認
        $this->assertNotNull($keyword2);
        $keyword3 = Bath::where('name', 'like', "%かかかかかかk%")->first(); // nameカラムに、「かかかかかかk」がないことの確認
        $this->assertNull($keyword3);
    }
}

何かもっといいやり方がありそう。。。

●<テストデータ投稿テスト>

ファクトリーを作成してテストを行います

$ php artisan make:factory PostFactory
PostFactory.php
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Models\Post;
use Faker\Generator as Faker;
use Illuminate\Http\UploadedFile;

$factory->define(Post::class, function (Faker $faker) {
    return [
        'title' => $faker->name,
        'thoughts' => $faker->name,
        'main_image_path' => UploadedFile::fake()->create('main.jpeg', 10)->store('uploads'),
        'eval_cd' => $faker->randomElement([0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5]),
    ];
});

ToPostTest.php
<?php

namespace Tests\Feature\Post;

use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;

/**
 * お風呂投稿 Featureテスト
 */
class ToPostTest extends TestCase
{

    use DatabaseTransactions; // FactoryのテストデータをDBに保存させない

    /**
     * 投稿画面 投稿処理、投稿後リダイレクト、DB保存テスト
     *
     * @return void
     */
    public function testPost()
    {
            $user = factory(User::class)->create();
            $post = factory(Post::class)->create();

            $this->actingAs($user)->get('/post/mypost');

            $this->withoutExceptionHandling(); // Exception発生後のスルー回避

            $data = [
                'title' => $post->title,
                'thoughts' => $post->thoughts,
            ];

            $response = $this->withoutMiddleware()->post('/post/topost', $data); // ミドルウェアを通さない

            $response->assertRedirect('/post/mypost'); // リダイレクトテスト
            $this->assertDatabaseHas('posts', $data); // DBテスト(postsテーブル)
    }
}

factory()->create()

・Eloquentのsaveメソッドを使用しデータベースへ保存
factory()->make()だと、インスタンスだけ作成

use DatabaseTransactions;

・FactoryのテストデータをDBに保存させないようにしています。

$this->withoutExceptionHandling()の存在意義について

・記載がないと、テスト対象のスクリプト内でExceptionが発生してもスルーされる
・Webサーバーはステータス500を返しているはずのところを、$response->assertStatus(200)が通る
・例外処理のテストでもない限り、$this->withoutExceptionHandling()は記載すべき

4. 参考

10
5
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
10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?