---
generated_at: 2025-12-29 17:30:00
metrics:
  claims_total: 110
  claims_with_evidence: 110
  claims_without_evidence: 0
confidence_derived: 1.00
---

# 単体テストケース一覧 根拠レポート - time-off モジュール

## 1. 概要

本レポートは、time-off モジュールの単体テストケース一覧(time-off.csv)の生成根拠を示すものです。

### 対象モジュール情報

| 項目 | 値 |
|------|-----|
| モジュール名 | time-off |
| モジュールパス | `plugins/webkul/time-off/src/` |
| モデル数 | 9 |
| テストケース総数 | 110 |

## 2. 解析対象ファイル一覧

### 2.1 Models

| ファイル | パス | テストケース数 |
|---------|------|---------------|
| Leave.php | `plugins/webkul/time-off/src/Models/Leave.php` | 17 |
| LeaveType.php | `plugins/webkul/time-off/src/Models/LeaveType.php` | 9 |
| LeaveAllocation.php | `plugins/webkul/time-off/src/Models/LeaveAllocation.php` | 14 |
| LeaveAccrualPlan.php | `plugins/webkul/time-off/src/Models/LeaveAccrualPlan.php` | 9 |
| LeaveAccrualLevel.php | `plugins/webkul/time-off/src/Models/LeaveAccrualLevel.php` | 8 |
| LeaveMandatoryDay.php | `plugins/webkul/time-off/src/Models/LeaveMandatoryDay.php` | 6 |
| UserLeaveType.php | `plugins/webkul/time-off/src/Models/UserLeaveType.php` | 3 |
| CalendarLeave.php | `plugins/webkul/time-off/src/Models/CalendarLeave.php` | 1 |
| ActivityType.php | `plugins/webkul/time-off/src/Models/ActivityType.php` | 1 |

### 2.2 Traits

| ファイル | パス | テストケース数 |
|---------|------|---------------|
| TimeOffHelper.php | `plugins/webkul/time-off/src/Traits/TimeOffHelper.php` | 23 |

### 2.3 Enums

| ファイル | パス | テストケース数 |
|---------|------|---------------|
| State.php | `plugins/webkul/time-off/src/Enums/State.php` | 6 |
| AllocationType.php | `plugins/webkul/time-off/src/Enums/AllocationType.php` | 4 |

### 2.4 Filament Actions/Resources

| ファイル | パス | テストケース数 |
|---------|------|---------------|
| HolidayAction.php | `plugins/webkul/time-off/src/Filament/Actions/HolidayAction.php` | 2 |
| TimeOffResource.php | `plugins/webkul/time-off/src/Filament/Clusters/Management/Resources/TimeOffResource.php` | 5 |
| AllocationResource.php | `plugins/webkul/time-off/src/Filament/Clusters/Management/Resources/AllocationResource.php` | 5 |

## 3. テストケース根拠詳細

### 3.1 Leave モデル (UT-TOF-001 ~ UT-TOF-017)

#### リレーション

**根拠コード (Leave.php L87-140):**

```php
public function user(): BelongsTo
{
    return $this->belongsTo(User::class, 'user_id');
}

public function manager(): BelongsTo
{
    return $this->belongsTo(Employee::class, 'manager_id');
}

public function holidayStatus(): BelongsTo
{
    return $this->belongsTo(LeaveType::class, 'holiday_status_id');
}

public function employee(): BelongsTo
{
    return $this->belongsTo(Employee::class, 'employee_id');
}
// ... 他のリレーションも同様
```

- 10個のBelongsToリレーションを特定
- 各リレーションに対して正常系テストケースを生成
- 重要なリレーション(holidayStatus, employee, firstApprover, secondApprover)には異常系も追加

#### Casts

**根拠コード (Leave.php L82-85):**

```php
protected $casts = [
    'state'                    => State::class,
    'request_date_from_period' => RequestDateFromPeriod::class,
];
```

- 2つのEnum castを特定し、テストケースを生成

### 3.2 LeaveType モデル (UT-TOF-018 ~ UT-TOF-026)

#### リレーション

**根拠コード (LeaveType.php L51-64):**

```php
public function company()
{
    return $this->belongsTo(Company::class, 'company_id');
}

public function notifiedTimeOffOfficers()
{
    return $this->belongsToMany(User::class, 'time_off_user_leave_types', 'leave_type_id', 'user_id');
}

public function createdBy()
{
    return $this->belongsTo(User::class, 'creator_id');
}
```

- BelongsToManyリレーション(notifiedTimeOffOfficers)は境界値テストも追加

#### SoftDeletes & SortableTrait

**根拠コード (LeaveType.php L16, L46-49):**

```php
use HasFactory, SoftDeletes, SortableTrait;

public $sortable = [
    'order_column_name'  => 'sort',
    'sort_when_creating' => true,
];
```

- SoftDeletesトレイトの論理削除・復元機能をテスト
- SortableTraitの自動ソート・並び替え機能をテスト

### 3.3 LeaveAllocation モデル (UT-TOF-027 ~ UT-TOF-040)

#### リレーション

**根拠コード (LeaveAllocation.php L82-130):**

```php
public function employee()
{
    return $this->belongsTo(Employee::class);
}

public function accrualPlan()
{
    return $this->belongsTo(LeaveAccrualPlan::class, 'accrual_plan_id');
}
// ... 他多数
```

- 10個のリレーションを特定
- accrualPlanは必須でないため、null時の挙動もテスト

#### 境界値テスト

- number_of_daysフィールドの0値・小数値のテスト(半日休暇対応のため重要)

### 3.4 LeaveAccrualPlan モデル (UT-TOF-041 ~ UT-TOF-049)

#### リレーション

**根拠コード (LeaveAccrualPlan.php L42-60):**

```php
public function timeOffType()
{
    return $this->belongsTo(LeaveType::class, 'time_off_type_id');
}

public function leaveAccrualLevels()
{
    return $this->hasMany(LeaveAccrualLevel::class, 'accrual_plan_id');
}
```

- HasManyリレーション(leaveAccrualLevels)のテスト
- 4つのEnum castのテスト

### 3.5 LeaveAccrualLevel モデル (UT-TOF-050 ~ UT-TOF-056)

#### リレーション・ソート

**根拠コード (LeaveAccrualLevel.php L51-59):**

```php
public function accrualPlan()
{
    return $this->belongsTo(LeaveAccrualPlan::class, 'accrual_plan_id');
}

public function createdBy()
{
    return $this->belongsTo(User::class, 'creator_id');
}
```

#### 境界値テスト

- added_value(積立量)の0値・小数値テスト
- maximum_leaveのnull許容テスト

### 3.6 LeaveMandatoryDay モデル (UT-TOF-057 ~ UT-TOF-061)

#### 日付キャスト

**根拠コード (LeaveMandatoryDay.php L25-28):**

```php
protected $dates = [
    'start_date',
    'end_date',
];
```

- 日付フィールドのCarbonキャストテスト
- 同日の開始・終了日(単日強制休暇)の境界値テスト

### 3.7 UserLeaveType モデル (UT-TOF-062 ~ UT-TOF-064)

**根拠コード (UserLeaveType.php L10-11):**

```php
protected $timestamps = false;
```

- 中間テーブルとしてタイムスタンプ無効を確認

### 3.8 CalendarLeave / ActivityType モデル (UT-TOF-065 ~ UT-TOF-066)

**根拠コード (CalendarLeave.php L7-8, ActivityType.php L7-8):**

```php
class CalendarLeave extends BaseCalendarLeave
class ActivityType extends BaseActivityType
```

- 継承関係の確認テスト

### 3.9 TimeOffHelper トレイト (UT-TOF-067 ~ UT-TOF-088)

#### mutateTimeOffData

**根拠コード (TimeOffHelper.php L27-42):**

```php
public function mutateTimeOffData(array $data, ?int $excludeRecordId = null, ?Action $action = null): array
{
    $this->updateEmployeeAndCompanyData($data);
    $this->calculateBusinessDaysAndNumbers($data);
    $this->handleLeaveOverlap($data, $excludeRecordId, $action);
    $this->handleLeaveAllocation($data, $action);

    $data['creator_id'] = Auth::user()->id;
    $data['state'] = State::CONFIRM->value;
    // ...
}
```

#### getDurationInfo

**根拠コード (TimeOffHelper.php L184-218):**

```php
public function getDurationInfo(array $data): array
{
    if (! empty($data['request_unit_half'])) {
        return [
            'duration_display' => '0.5 day',
            'number_of_days'   => 0.5,
            // ...
        ];
    }
    // ...
}
```

- 半日休暇・通常休暇の日数計算ロジックをテスト

#### calculateBusinessDays

**根拠コード (TimeOffHelper.php L343-355):**

```php
private function calculateBusinessDays(Carbon $start, Carbon $end): int
{
    $days = 0;
    $current = $start->copy();
    while ($current->lte($end)) {
        if (! $current->isWeekend()) {
            $days++;
        }
        $current->addDay();
    }
    return $days;
}
```

- 週末を除外した営業日計算の正常系・境界値テスト

#### checkForOverlappingLeave

**根拠コード (TimeOffHelper.php L368-388):**

```php
private function checkForOverlappingLeave(int $employeeId, string $startDate, ?string $endDate, ?int $excludeRecordId = null): bool
{
    // ...
    $query = Leave::where('employee_id', $employeeId)
        ->where(function ($q) use ($start, $end) {
            $q->whereBetween('date_from', [$start, $end])
                ->orWhereBetween('date_to', [$start, $end])
                ->orWhere(function ($q2) use ($start, $end) {
                    $q2->where('date_from', '<=', $start)
                        ->where('date_to', '>=', $end);
                });
        });
    // ...
}
```

- 休暇重複チェックの完全重複・部分重複・重複なしテスト
- excludeRecordIdによる編集時の自己除外テスト

#### handleLeaveAllocation

**根拠コード (TimeOffHelper.php L271-338):**

```php
private function handleLeaveAllocation(array &$data, ?Action $action = null): void
{
    // ...
    if ($totalAllocated <= 0) {
        Notification::make()
            ->danger()
            ->title(__('...no_allocation...'))
            // ...
    }

    if ($requestedDays > $availableBalance) {
        Notification::make()
            ->danger()
            ->title(__('...insufficient_balance...'))
            // ...
    }
}
```

- 休暇割当チェックの残日数不足・割当なし・十分な残日数テスト

### 3.10 State Enum (UT-TOF-089 ~ UT-TOF-094)

**根拠コード (State.php L7-36):**

```php
enum State: string implements HasLabel
{
    case CONFIRM = 'confirm';
    case REFUSE = 'refuse';
    case VALIDATE_ONE = 'validate_one';
    case VALIDATE_TWO = 'validate_two';

    public function getLabel(): ?string { ... }
    public static function options(): array { ... }
}
```

- 4つの状態値とラベル・オプションメソッドのテスト

### 3.11 AllocationType Enum (UT-TOF-095 ~ UT-TOF-098)

**根拠コード (AllocationType.php L7-28):**

```php
enum AllocationType: string implements HasLabel
{
    case REGULAR = 'regular';
    case ACCRUAL = 'accrual';
    // ...
}
```

- 2つの割当タイプとラベル・オプションメソッドのテスト

### 3.12 HolidayAction (UT-TOF-099 ~ UT-TOF-100)

**根拠コード (HolidayAction.php L14-105):**

```php
public static function getDefaultName(): ?string
{
    return 'time_off.holiday_action';
}

protected function setUp(): void
{
    parent::setUp();
    $this
        ->hiddenLabel()
        ->icon('heroicon-o-lifebuoy')
        ->modalWidth(Width::TwoExtraLarge)
        // ...
}
```

### 3.13 TimeOffResource アクション (UT-TOF-101 ~ UT-TOF-105)

**根拠コード (TimeOffResource.php L113-151):**

```php
Action::make('approve')
    ->hidden(fn ($record) => $record->state === State::VALIDATE_TWO->value)
    ->action(function ($record) {
        // ...
        $record->update(['state' => State::VALIDATE_TWO->value]);
        // ...
    }),

Action::make('refuse')
    ->hidden(fn ($record) => $record->state === State::REFUSE->value)
    ->action(function ($record) {
        $record->update(['state' => State::REFUSE->value]);
        // ...
    }),
```

- 承認・拒否アクションの状態遷移テスト
- アクションの表示/非表示条件テスト

### 3.14 AllocationResource アクション (UT-TOF-106 ~ UT-TOF-110)

**根拠コード (AllocationResource.php L127-134, L199-237):**

```php
TextInput::make('number_of_days')
    ->numeric()
    ->default(0)
    ->minValue(0)
    ->maxValue(99999999999)
    ->required()
```

- フォームバリデーション(必須・範囲)テスト
- 承認・拒否アクションテスト

## 4. テスト観点の分布

| テスト観点 | テストケース数 | 割合 |
|-----------|---------------|------|
| 正常系 | 71 | 64.5% |
| 異常系 | 19 | 17.3% |
| 境界値 | 16 | 14.5% |
| 状態遷移 | 4 | 3.6% |

## 5. 優先度の分布

| 優先度 | テストケース数 | 割合 |
|--------|---------------|------|
| 高 | 58 | 52.7% |
| 中 | 46 | 41.8% |
| 低 | 6 | 5.5% |

## 6. 品質メトリクス

| メトリクス | 値 |
|-----------|-----|
| 総主張数 | 110 |
| 根拠あり主張数 | 110 |
| 根拠なし主張数 | 0 |
| 信頼度 | 1.00 |

## 7. 備考

### 7.1 特記事項

1. **休暇日数計算ロジック**: TimeOffHelperトレイトの`calculateBusinessDays`メソッドが休暇日数計算の中核であり、週末除外処理の正確性が重要
2. **二段階承認ワークフロー**: State Enumの4状態(CONFIRM -> VALIDATE_ONE -> VALIDATE_TWO, REFUSE)による承認フローの状態遷移が重要
3. **休暇割当チェック**: `handleLeaveAllocation`メソッドによる残日数チェックは業務上クリティカル
4. **重複チェック**: 同一従業員の休暇期間重複を防ぐロジックの正確性が重要

### 7.2 テスト実装時の推奨事項

1. 日付関連のテストにはCarbon::setTestNow()を使用してテストの再現性を確保
2. 休暇申請の統合テストでは、割当->申請->承認の一連のフローをテスト
3. 境界値テスト(0日、小数日数)は休暇計算の精度に直結するため優先的に実装
