Skip to content

Commit ac4ed3a

Browse files
committed
Add CI/CD with automated testing
1 parent 2f51176 commit ac4ed3a

File tree

5 files changed

+256
-0
lines changed

5 files changed

+256
-0
lines changed

.env.testing

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
APP_NAME=Laravel
2+
APP_ENV=testing
3+
APP_KEY=
4+
APP_DEBUG=true
5+
APP_URL=http://localhost
6+
7+
APP_LOCALE=en
8+
APP_FALLBACK_LOCALE=en
9+
APP_FAKER_LOCALE=en_US
10+
11+
LOG_CHANNEL=stack
12+
LOG_LEVEL=debug
13+
14+
# テスト用 DB 設定
15+
DB_CONNECTION=mysql
16+
DB_HOST=127.0.0.1
17+
DB_PORT=3306
18+
DB_DATABASE=testing
19+
DB_USERNAME=root
20+
DB_PASSWORD=password
21+
22+
# テスト用はメモリ上で動作(高速化)
23+
SESSION_DRIVER=array
24+
SESSION_LIFETIME=120
25+
26+
BROADCAST_CONNECTION=log
27+
FILESYSTEM_DISK=local
28+
QUEUE_CONNECTION=sync
29+
30+
CACHE_STORE=array
31+
32+
# テスト用ダミー値
33+
MAIL_MAILER=array
34+
MAIL_FROM_ADDRESS="test@example.com"
35+
MAIL_FROM_NAME="${APP_NAME}"
36+
37+
# テスト用 Google OAuth ダミー値
38+
GOOGLE_CLIENT_ID=test-client-id
39+
GOOGLE_CLIENT_SECRET=test-client-secret
40+
GOOGLE_REDIRECT_URI=http://localhost/callback
41+
42+
# CORS(テストでは不要だが念のため)
43+
CORS_ALLOWED_ORIGINS=http://localhost
44+
SANCTUM_STATEFUL_DOMAINS=localhost
45+
SESSION_DOMAIN=localhost

.github/workflows/deploy.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,65 @@ on:
66
- main
77

88
jobs:
9+
# ========================================
10+
# テストジョブ(GitHub Actions の仮想マシン上で実行)
11+
# ========================================
12+
test:
13+
runs-on: ubuntu-latest # GitHub が提供する Ubuntu 環境(一時的)
14+
15+
# テスト用の MySQL サーバーを起動
16+
# このMySQLはテスト実行中だけ存在し、終了後は削除される
17+
services:
18+
mysql:
19+
image: mysql:8.0 # Docker イメージから MySQL 8.0 を起動
20+
env:
21+
MYSQL_ROOT_PASSWORD: password # root のパスワード
22+
MYSQL_DATABASE: testing # テスト用DBを自動作成
23+
ports:
24+
- 3306:3306 # MySQL のポートを公開
25+
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
26+
27+
steps:
28+
# ステップ1: リポジトリのコードを取得
29+
# あなたが push したコードを GitHub Actions の環境にダウンロード
30+
- name: Checkout code
31+
uses: actions/checkout@v4
32+
33+
# ステップ2: PHP 8.3 をインストール
34+
# GitHub の環境には最初 PHP が入っていないのでインストール
35+
- name: Setup PHP
36+
uses: shivammathur/setup-php@v2
37+
with:
38+
php-version: '8.3' # PHP 8.3 を指定
39+
extensions: mbstring, pdo, pdo_mysql # Laravel に必要な拡張機能
40+
coverage: none # カバレッジ計測は不要
41+
42+
# ステップ3: .env ファイルを作成
43+
# リポジトリには .env はないので .env.testing をコピー
44+
- name: Copy .env
45+
run: cp .env.testing .env
46+
47+
# ステップ4: Composer で Laravel の依存パッケージをインストール
48+
# ここで Laravel やその他のパッケージがインストールされる
49+
# vendor/ ディレクトリが作成される
50+
- name: Install dependencies
51+
run: composer install --prefer-dist --no-progress --no-interaction
52+
53+
# ステップ5: Laravel のアプリケーションキーを生成
54+
# .env の APP_KEY を設定(暗号化に使用)
55+
- name: Generate application key
56+
run: php artisan key:generate
57+
58+
# ステップ6: テストを実行
59+
# ここで AuthTest.php などのテストが実行される
60+
- name: Run tests
61+
run: php artisan test # PHPUnit を実行
62+
63+
# ========================================
64+
# デプロイジョブ(本番環境 Lightsail へデプロイ)
65+
# ========================================
966
deploy:
67+
needs: test # test ジョブが成功した場合のみ実行される
1068
runs-on: ubuntu-latest
1169

1270
steps:

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,30 @@ laravel-rds-db の保持されたバックアップを選択
877877
878878
システムスナップショットが後程削除されるのを確認
879879
880+
881+
### 「ユーザー認証とロール(権限)」 をテスト
882+
883+
database\factories\UserFactory.phpを修正
884+
885+
886+
テストファイル作成
887+
```bash
888+
./vendor/bin/sail artisan make:test Api/AuthTest
889+
```
890+
テスト実行
891+
```bash
892+
./vendor/bin/sail artisan test --filter=AuthTest
893+
```
894+
895+
#### CI/CD にテスト組み込み
896+
897+
.github\workflows\deploy.ymlを追記
898+
.env.testingを作成
899+
900+
901+
902+
903+
880904
## プロジェクト方針と戦略策定
881905
882906
1. **ポートフォリオとしての活用**

database/factories/UserFactory.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public function definition(): array
2929
'email_verified_at' => now(),
3030
'password' => static::$password ??= Hash::make('password'),
3131
'remember_token' => Str::random(10),
32+
'google_id' => null,
33+
'avatar' => null,
3234
];
3335
}
3436

@@ -41,4 +43,15 @@ public function unverified(): static
4143
'email_verified_at' => null,
4244
]);
4345
}
46+
47+
/**
48+
* ロール付きユーザーを作成
49+
*/
50+
public function withRole(string $roleName): static
51+
{
52+
return $this->afterCreating(function ($user) use ($roleName) {
53+
$role = \App\Models\Role::firstOrCreate(['name' => $roleName]);
54+
$user->roles()->attach($role);
55+
});
56+
}
4457
}

tests/Feature/Api/AuthTest.php

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?php
2+
3+
namespace Tests\Feature\Api;
4+
5+
use Illuminate\Foundation\Testing\RefreshDatabase;
6+
use Illuminate\Foundation\Testing\WithFaker;
7+
use Tests\TestCase;
8+
use App\Models\User;
9+
10+
class AuthTest extends TestCase
11+
{
12+
use RefreshDatabase; // テスト後データベースをリセット
13+
/**
14+
* ログインテスト
15+
*/
16+
public function test_succeed_login(): void
17+
{
18+
// 1. テストユーザーを作成
19+
$user = User::factory()->create([
20+
'email' => 'test@example.com',
21+
'password' => bcrypt('password123'),
22+
]);
23+
24+
// 2. ログインAPIを叩く
25+
$response = $this->postJson('/api/login', [
26+
'email' => 'test@example.com',
27+
'password' => 'password123',
28+
]);
29+
30+
// 3. 検証
31+
$response->assertStatus(200); // 200 OKか?
32+
$response->assertJsonStructure(['authToken', 'user']); // authTokenとuserが返されるか?
33+
}
34+
35+
/**
36+
* ログイン失敗テスト
37+
*/
38+
public function test_failed_login(): void
39+
{
40+
$response = $this->postJson('/api/login', [
41+
'email' => 'test@example.com',
42+
'password' => 'wrongpassword', // 間違ったパスワード
43+
]);
44+
45+
$response->assertStatus(401); // 401 Unauthorizedか?
46+
$response->assertJsonStructure(['message']); // messageが返されるか?
47+
}
48+
49+
/**
50+
* adminロールを持つユーザーが作成できる
51+
*/
52+
public function test_create_user_with_admin_role(): void
53+
{
54+
// adminロール付きユーザーを作成
55+
$user = User::factory()->withRole('admin')->create();
56+
57+
// 検証
58+
$this->assertTrue($user->roles->pluck('name')->contains('admin'));
59+
}
60+
61+
/**
62+
* paidロールを持つユーザーが作成できる
63+
*/
64+
public function test_create_user_with_paid_role(): void
65+
{
66+
// paidロール付きユーザーを作成
67+
$user = User::factory()->withRole('paid')->create();
68+
69+
// 検証
70+
$this->assertTrue($user->roles->pluck('name')->contains('paid'));
71+
}
72+
73+
/**
74+
* ロールなしユーザーが作成できる
75+
*/
76+
public function test_create_user_without_role(): void
77+
{
78+
// 通常ユーザーを作成
79+
$user = User::factory()->create();
80+
81+
// 検証
82+
$this->assertCount(0, $user->roles);
83+
}
84+
85+
/**
86+
* ログイン済みユーザーは自分の情報を取得できる
87+
*/
88+
public function test_authenticated_user_can_get_profile(): void
89+
{
90+
// ユーザーを作成
91+
$user = User::factory()->create();
92+
93+
// 認証してリクエスト
94+
$response = $this->actingAs($user, 'sanctum')
95+
->getJson('/api/user');
96+
97+
// 検証
98+
$response->assertStatus(200);
99+
$response->assertJson([
100+
'id' => $user->id,
101+
'email' => $user->email,
102+
]);
103+
}
104+
105+
/**
106+
* 未ログインユーザーは401エラー
107+
*/
108+
public function test_unauthenticated_user_cannot_get_profile(): void
109+
{
110+
// 認証なしでリクエスト
111+
$response = $this->getJson('/api/user');
112+
113+
// 検証
114+
$response->assertStatus(401);
115+
}
116+
}

0 commit comments

Comments
 (0)