カテゴリ: Laravel 更新日: 2026/07/05

LaravelのFeatureテストとUnitテストの違いを理解しよう

LaravelのFeatureテストとUnitテストの違いを理解しよう
LaravelのFeatureテストとUnitテストの違いを理解しよう

先生と生徒の会話形式で理解しよう

生徒

「Laravelのテストには種類があるって聞いたんですが、どう違うんですか?」

先生

「Laravelには主にFeatureテストとUnitテストの2種類があります。それぞれ役割が違うんですよ。」

生徒

「具体的にはどんな時にどちらを使えばいいんですか?」

先生

「それでは、2つのテストの違いと使い分け方を詳しく見ていきましょう!」

1. FeatureテストとUnitテストの基本的な違い

1. FeatureテストとUnitテストの基本的な違い
1. FeatureテストとUnitテストの基本的な違い

LaravelのテストにはFeatureテストとUnitテストという2つの種類があります。この2つはテストする範囲が大きく異なります。料理に例えると分かりやすいでしょう。Unitテストは「塩の味が正しいか」という個別の調味料をチェックすることで、Featureテストは「完成した料理全体の味が美味しいか」を確認することです。

Unitテストは単体テストとも呼ばれ、プログラムの小さな部品一つ一つが正しく動くかを確認します。例えば、計算機能だけ、文字列処理だけ、といった単独の機能をテストします。一方、Featureテストは機能テストとも呼ばれ、ユーザーが実際に操作する一連の流れが正しく動くかを確認します。例えば、ログイン画面でメールアドレスとパスワードを入力して、ログインボタンを押したら正しくホーム画面に移動するか、という全体の流れをテストします。

2. Unitテストの特徴と使い方

2. Unitテストの特徴と使い方
2. Unitテストの特徴と使い方

Unitテストは、プログラムの最小単位であるメソッド(関数)クラスが正しく動作するかをテストします。他の部分に依存せず、独立してテストできることが特徴です。

例えば、消費税を計算するメソッドをテストしてみましょう。まず、計算用のクラスを作成します。

<?php

namespace App\Services;

class TaxCalculator
{
    public function calculate($price)
    {
        return $price * 1.1;
    }
}

このクラスをテストするUnitテストは以下のようになります。

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use App\Services\TaxCalculator;

class TaxCalculatorTest extends TestCase
{
    public function test_消費税計算が正しい()
    {
        $calculator = new TaxCalculator();
        $result = $calculator->calculate(1000);
        
        $this->assertEquals(1100, $result);
    }
}

このテストでは、1000円の商品に消費税を加えると1100円になることを確認しています。Unitテストは実行速度が速く、問題箇所を特定しやすいというメリットがあります。データベースやネットワーク通信などの外部リソースを使わないため、短時間で大量のテストを実行できます。

3. Featureテストの特徴と使い方

3. Featureテストの特徴と使い方
3. Featureテストの特徴と使い方

Featureテストは、ユーザーの視点から見た機能全体をテストします。実際のHTTPリクエスト(ウェブページへのアクセス)をシミュレートして、アプリケーション全体が正しく動作するかを確認します。

例えば、商品一覧ページが正しく表示されるかをテストしてみましょう。

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Models\Product;

class ProductListTest extends TestCase
{
    use RefreshDatabase;
    
    public function test_商品一覧ページが表示される()
    {
        Product::create([
            'name' => 'ノートパソコン',
            'price' => 80000
        ]);
        
        $response = $this->get('/products');
        
        $response->assertStatus(200);
        $response->assertSee('ノートパソコン');
    }
}

このテストでは、商品をデータベースに登録してから商品一覧ページにアクセスし、ページが正しく表示されることと、登録した商品名が画面に表示されることを確認しています。assertSeeメソッドは、指定した文字列が画面に表示されているかをチェックします。Featureテストは実際のユーザー体験に近いテストができるため、バグを見つけやすいという利点があります。

4. テストファイルの保存場所の違い

4. テストファイルの保存場所の違い
4. テストファイルの保存場所の違い

LaravelのプロジェクトではFeatureテストとUnitテストで保存場所が異なります。これはテストの種類を明確に区別するためです。

Unitテストの保存場所

tests/Unit/フォルダに保存します

Featureテストの保存場所

tests/Feature/フォルダに保存します

テストファイルを作成するときは、Laravelのartisanコマンドを使うと自動的に正しい場所に作成されます。Unitテストを作る場合は--unitオプションを付けます。

php artisan make:test TaxCalculatorTest --unit

Featureテストを作る場合は、オプションなしでコマンドを実行します。

php artisan make:test ProductListTest

このようにコマンド一つで、正しいフォルダに正しい形式のテストファイルが作成されるため、初心者でも迷わずテストを始められます。

5. テスト実行速度とテスト範囲の関係

5. テスト実行速度とテスト範囲の関係
5. テスト実行速度とテスト範囲の関係

FeatureテストとUnitテストでは、実行速度が大きく異なります。これはテスト範囲の違いによるものです。

Unitテストは小さな部品だけをテストするため、1つのテストが0.01秒程度で終わります。100個のUnitテストを実行しても1秒程度です。これは、データベースへの接続やファイルの読み書きなど、時間のかかる処理を含まないためです。

一方、Featureテストはアプリケーション全体を動かすため、1つのテストに0.1秒から1秒程度かかることがあります。データベースへのアクセス、ルーティング処理、ビューのレンダリング(画面の生成)など、多くの処理が含まれるためです。

比較項目 Unitテスト Featureテスト
実行速度 非常に速い やや遅い
テスト範囲 単一メソッドやクラス 機能全体の流れ
依存関係 独立している 多くの部品に依存
バグ特定 しやすい やや難しい

理想的なテスト構成は、Unitテストを多く書いて基礎を固め、重要な機能についてFeatureテストを書く形です。これをテストピラミッドと呼びます。ピラミッドの土台となる多数のUnitテストと、頂点となる少数のFeatureテストで、効率的にアプリケーションの品質を保証できます。

6. データベースを使うテストの違い

6. データベースを使うテストの違い
6. データベースを使うテストの違い

データベースを使う場合、FeatureテストとUnitテストでアプローチが異なります。Featureテストでは実際にデータベースを使ってテストすることが一般的ですが、Unitテストではできるだけデータベースを使わないようにします。

Featureテストでデータベースを使う例を見てみましょう。

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Models\User;

class UserRegistrationTest extends TestCase
{
    use RefreshDatabase;
    
    public function test_ユーザー登録ができる()
    {
        $response = $this->post('/register', [
            'name' => '田中花子',
            'email' => 'tanaka@example.com',
            'password' => 'password123',
            'password_confirmation' => 'password123'
        ]);
        
        $this->assertDatabaseHas('users', [
            'name' => '田中花子',
            'email' => 'tanaka@example.com'
        ]);
        
        $response->assertRedirect('/home');
    }
}

RefreshDatabaseトレイトを使うと、テスト実行後に自動的にデータベースがリセットされます。トレイトとは、複数のクラスで共通して使える機能をまとめたものです。これにより、テスト同士が干渉せず、常に同じ状態からテストを開始できます。

Unitテストでは、データベースの代わりにモック(偽物)を使うことが推奨されます。モックとは、実際のデータベースの代わりに動作する偽のオブジェクトです。これにより、テストが高速になり、外部システムへの依存を減らせます。

7. どちらのテストを先に書くべきか

7. どちらのテストを先に書くべきか
7. どちらのテストを先に書くべきか

初心者の方がよく迷うのが、FeatureテストとUnitテストのどちらを先に書くべきかという問題です。これには2つの考え方があります。

一つ目はアウトサイドインと呼ばれる方法です。これは外側(Feature)から内側(Unit)へ向かってテストを書く方法です。まずFeatureテストで全体の動作を確認してから、細かい部分をUnitテストで確認していきます。この方法は、ユーザー視点で重要な機能から開発を進められるメリットがあります。

二つ目はインサイドアウトと呼ばれる方法です。これは内側(Unit)から外側(Feature)へ向かってテストを書く方法です。まず小さな部品をUnitテストで確認してから、それらを組み合わせた全体の動作をFeatureテストで確認します。この方法は、基礎となる部品の品質を確保してから全体を構築できるメリットがあります。

どちらの方法を選ぶかは、プロジェクトの特性や個人の好みによります。小規模なプロジェクトや初心者の方は、理解しやすいアウトサイドインから始めることをおすすめします。実際にユーザーが使う機能をテストすることで、モチベーションも維持しやすくなります。

8. 実践的なテストの書き分け例

8. 実践的なテストの書き分け例
8. 実践的なテストの書き分け例

実際の開発では、機能に応じてFeatureテストとUnitテストを使い分けます。例えば、ECサイトの注文機能を開発する場合を考えてみましょう。

まず、注文金額を計算する部分はUnitテストで確認します。これは単純な計算処理なので、独立してテストできます。

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use App\Services\OrderCalculator;

class OrderCalculatorTest extends TestCase
{
    public function test_送料込みの合計金額が正しい()
    {
        $calculator = new OrderCalculator();
        
        $subtotal = 5000;
        $shipping = 500;
        $total = $calculator->calculateTotal($subtotal, $shipping);
        
        $this->assertEquals(5500, $total);
    }
}

一方、注文フォームから注文を送信して、確認画面に移動するという一連の流れはFeatureテストで確認します。

このように、計算ロジックなどのビジネスロジック(業務処理)はUnitテストで、ユーザーインターフェースを含む機能全体はFeatureテストで確認することで、効率的にテストできます。両方のテストを組み合わせることで、プログラムの品質を高いレベルで保つことができます。

9. テストを書く際の注意点

9. テストを書く際の注意点
9. テストを書く際の注意点

FeatureテストとUnitテストを書く際には、いくつかの注意点があります。まず、テスト名は日本語で書くと何をテストしているかが分かりやすくなります。test_商品が正しく登録されるのような名前なら、誰が見ても理解できます。

次に、一つのテストでは一つのことだけを確認するようにします。複数の機能を一つのテストで確認すると、どこで失敗したのか分かりにくくなります。これを単一責任の原則と呼びます。

また、テストは他のテストに依存しないように書きます。例えば、テストAが成功しないとテストBが実行できない、という状況は避けるべきです。各テストは独立して実行できる必要があります。

Featureテストを書く際は、テストデータの準備に時間がかかることがあります。その場合はファクトリーという機能を使うと便利です。ファクトリーは、テスト用のダミーデータを簡単に作成できる仕組みです。Laravelには標準でファクトリー機能が搭載されているので、積極的に活用しましょう。

最後に、テストのメンテナンスも重要です。プログラムを修正したら、それに対応するテストも更新する必要があります。テストが古くなって実際の動作と合わなくなると、テストの意味がなくなってしまいます。定期的にテストコードも見直して、最新の状態に保つようにしましょう。

まとめ

まとめ
まとめ

Laravelの開発において、テストコードを書くことはアプリケーションの品質を担保するために欠かせない工程です。今回学習したFeatureテスト(機能テスト)Unitテスト(単体テスト)には、それぞれ明確な役割と得意分野があることが分かりましたね。

Unitテストは、数学の計算式や文字列の加工といった「純粋なロジック」を検証するのに最適です。実行速度が極めて速いため、開発中に何度も実行して、ロジックに間違いがないか即座にフィードバックを得ることができます。一方で、Featureテストは「ユーザーがブラウザを通じて行う操作」をシミュレートします。データベースとの連携や画面の遷移、バリデーションの挙動など、システム全体が連携して正しく動いているかを一気に確認できる頼もしい存在です。

テスト作成のポイントをおさらい

テストを作成する際は、Laravelの職人コマンド(Artisan)を活用するのが一番の近道です。フォルダ構成を間違えると、テストが正しく実行されない原因になるため、以下のコマンドを指に覚え込ませておきましょう。

Unitテスト(単体テスト)の作成

php artisan make:test SampleUnitTest --unit

Featureテスト(機能テスト)の作成

php artisan make:test SampleFeatureTest

現場で使えるテストコードの書き分け例

例えば、ユーザーの年齢から「成人かどうか」を判定するロジックはUnitテストで書き、実際に「登録フォームからデータを送ってデータベースに保存されるか」はFeatureテストで書くのが一般的です。具体的なコードのイメージをもう一度見てみましょう。

1. ロジックを徹底的に検証するUnitテスト

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use App\Models\User;

class UserLogicTest extends TestCase
{
    /**
     * 年齢判定ロジックの単体テスト
     */
    public function test_20歳以上なら成人と判定されること()
    {
        // 擬似的なデータやロジックのみを検証(DBは使わない)
        $isAdult = function($age) {
            return $age >= 20;
        };

        $this->assertTrue($isAdult(20));
        $this->assertFalse($isAdult(19));
    }
}

2. 画面とDBの連携を検証するFeatureテスト

<?php

namespace Tests\Feature;

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

class UserAccessTest extends TestCase
{
    use RefreshDatabase;

    /**
     * プロフィールページへのアクセス確認
     */
    public function test_ログイン後にプロフィールが表示される()
    {
        // 実際のURLにアクセスして挙動を確認
        $response = $this->get('/profile');

        // ページが正常に表示され、特定の文字が含まれているか
        $response->assertStatus(200);
        $response->assertSee('マイページ');
    }
}

このように、小さな部品はUnitで、大きな流れはFeatureで守るという「使い分け」ができるようになると、Laravelでの開発効率は劇的に向上します。最初はFeatureテストから書き始めて、ユーザーから見える動きを保証することからスタートするのが挫折しないコツですよ。

先生と生徒の振り返り会話

生徒

「先生、ありがとうございます!FeatureテストとUnitテストの使い分けがかなりスッキリしました。Featureテストは『ユーザーが見る画面や全体の動き』、Unitテストは『プログラムの小さな計算やロジック』を確認するんですね。」

先生

「その通りです!よく理解できましたね。料理に例えると、Unitテストは『卵が腐っていないか』のチェックで、Featureテストは『オムライスとして完成していて美味しいか』をチェックするようなイメージです。」

生徒

「なるほど、分かりやすいです!でも、全部Featureテストで書いちゃダメなんですか?その方が安心な気がするんですけど……。」

先生

「鋭い質問ですね!確かにFeatureテストだけでも安心感はありますが、テストの数が増えてくると実行に時間がかかるようになってしまいます。何百個もテストがある場合、Unitテストなら数秒で終わるのに、Featureテストばかりだと数分待たされることもあるんですよ。」

生徒

「数分も!それは開発のテンポが悪くなりそうですね。だからこそ、計算などは速いUnitテストに任せて、役割を分担させるのが大事なんですね。」

先生

「その通り!あとはバグが見つかった時も、Unitテストなら『この関数のここが間違っている』とすぐ分かりますが、Featureテストだと『どこかでエラーが起きた』となり、原因究明に少し時間がかかることもあります。両方をバランスよく組み合わせるのがプロの技ですよ。」

生徒

「バランスが大事なんですね。まずはFeatureテストで基本的な画面の表示を確認するところから始めて、徐々にUnitテストにも挑戦してみようと思います!」

先生

「素晴らしい意気込みです!テストコードは将来の自分を助けてくれる大切な資産になります。ぜひ楽しみながら書いてみてくださいね。」

カテゴリの一覧へ
新着記事
New1
Symfony
Symfonyのサービスとは?役割と基本概念を初心者向けにやさしく解説
New2
Laravel
Laravelでリダイレクトやフラッシュメッセージをテストする方法を完全解説!初心者向けLaravelテスト入門
New4
CodeIgniter
CodeIgniterのセキュリティ対策を完全ガイド!初心者が守るべき基本設定
人気記事
No.2
Java&Spring記事人気No2
Laravel
LaravelでReactコンポーネントを組み込む方法完全ガイド!JSX対応でフロントエンド連携を学ぼう
No.3
Java&Spring記事人気No3
Laravel
LaravelのRESTfulコントローラ設計のベストプラクティスを初心者向けにわかりやすく解説
No.4
Java&Spring記事人気No4
Laravel
Laravelのold()関数でフォーム再表示時に値を保持する方法
No.5
Java&Spring記事人気No5
Symfony
Symfonyのインストール方法!CLIとComposerの導入手順まとめ
No.6
Java&Spring記事人気No6
Laravel
LaravelをDockerで動かすメリットと導入の全体像を徹底解説!初心者向け入門ガイド
No.7
Java&Spring記事人気No7
Symfony
Symfonyでバリデーションをコントローラに組み込む方法を徹底解説!初心者にもやさしい入力チェックの基本
No.8
Java&Spring記事人気No8
Laravel
Laravelのデータベース設定方法を完全ガイド!初心者でもわかる.envファイルの使い方