# Issue #20: エントリポイントテストの sys.argv 問題修正

## 優先度: 中

## 概要

エントリポイントのテスト実行時、pytest の引数（`-v` など）が `sys.argv` 経由でエントリポイントに渡されてしまい、予期しないエラーが発生する。

## 現状の問題

### テストコード例

```python
# tests/entries/test_main.py
from src.main import main

def test_main_returns_success():
    result = main()
    assert result["status"] == "success"
```

### 実行結果

```bash
$ pytest tests/entries/test_main.py -v
E   typer.exceptions.BadParameter: Invalid value for argument
```

### 原因

`@entry_point` デコレータが内部で Typer を使用しており、テスト実行時に `sys.argv` から pytest の引数を拾ってしまう。

```python
sys.argv = ['pytest', '-v', 'tests/entries/test_main.py']
# ↑ これが entry_point 内で解釈されてエラー
```

## 期待する動作

テスト内でエントリポイント関数を直接呼び出した場合、`sys.argv` の影響を受けずに正常に実行される。

## 解決策の選択肢

### Option A: テストテンプレートで sys.argv をモック（推奨）

自動生成されるテストテンプレートに `sys.argv` のモック処理を含める:

```python
# tests/entries/test_main.py
import sys
from unittest.mock import patch

def test_main_returns_success():
    with patch.object(sys, 'argv', ['main']):
        from src.main import main
        result = main()
        assert result["status"] == "success"
```

### Option B: @entry_point に test_mode フラグ追加

```python
@entry_point(test_mode=True)  # sys.argv を無視
def main():
    ...
```

### Option C: 別の呼び出し方法を提供

```python
# entry_point 内部関数を直接テスト可能にする
from src.main import _main_impl  # 内部実装

def test_main():
    result = _main_impl()  # Typer なしで呼び出し
    assert result["status"] == "success"
```

### Option D: CliRunner を使用（Typer標準）

```python
from typer.testing import CliRunner
from src.main import app  # Typer app

runner = CliRunner()

def test_main():
    result = runner.invoke(app, [])
    assert result.exit_code == 0
```

## 推奨実装（Option A + D のハイブリッド）

### 1. テストテンプレート改善

`railway new entry` で生成されるテストに CliRunner を使用:

```python
# tests/entries/test_{name}.py
"""Tests for {name} entry point."""

from typer.testing import CliRunner

runner = CliRunner()


class Test{ClassName}:
    """Test suite for {name} entry point."""

    def test_{name}_runs_successfully(self):
        """Entry point should complete without error."""
        from entries.{name} import app

        result = runner.invoke(app, [])
        assert result.exit_code == 0

    def test_{name}_with_args(self):
        """Test with command line arguments."""
        from entries.{name} import app

        result = runner.invoke(app, ["--help"])
        assert result.exit_code == 0
```

### 2. @entry_point の内部実装分離

```python
# railway/core/decorators.py
def entry_point(func=None, *, name=None):
    def decorator(f):
        # 内部実装を保持
        f._impl = f  # 元の関数を保存

        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            # Typer 経由の呼び出し
            ...

        wrapper._impl = f  # テストから直接呼び出し可能
        return wrapper
    ...
```

テストでは:

```python
def test_main_impl():
    from src.main import main
    result = main._impl()  # Typer をバイパス
    assert result["status"] == "success"
```

### 3. ドキュメント追加

TUTORIAL.md にエントリポイントのテスト方法を追記:

```markdown
### エントリポイントのテスト

エントリポイントは Typer を使用しているため、CliRunner でテストします:

\`\`\`python
from typer.testing import CliRunner
runner = CliRunner()

def test_main():
    result = runner.invoke(app, [])
    assert result.exit_code == 0
\`\`\`
```

## 受け入れ条件

- [ ] `railway new entry` で生成されたテストが即座に実行可能
- [ ] pytest 引数がエントリポイントに影響しない
- [ ] CliRunner を使用したテストパターンがテンプレートに含まれる
- [ ] TUTORIAL.md にエントリポイントのテスト方法が記載される

## 関連

- レビュー3（2026-01-19）: テスト体験 7/10
- Issue #19: テストテンプレート改善
- Typer ドキュメント: Testing
