Skip to content
lorairo-test-generator logo

LoRAIro Test Generator Skill

lorairo-test-generator

Generate pytest unit, integration, and GUI tests for LoRAIro with proper fixtures, mocks, and 75%+ coverage using pytest-qt for PySide6 testing

SKILL.md

Full skill instructions

LoRAIro Test Generator Skill

このSkillは、LoRAIroプロジェクトにおけるpytest+pytest-qtを使ったテスト生成のベストプラクティスを提供します。

使用タイミング

  • 新機能実装後のテスト作成
  • 既存コードのテストカバレッジ向上
  • リファクタリング後の回帰テスト作成
  • GUI コンポーネントのテスト実装

LoRAIroのテスト戦略

テストカテゴリ (pytest markers)

# Unit tests: ビジネスロジック、単一関数/クラス
@pytest.mark.unit
def test_calculate_score():
    assert calculate_score(10, 20) == 0.5

# Integration tests: 複数コンポーネント統合
@pytest.mark.integration
def test_repository_service_integration():
    service = ImageProcessingService(repository)
    result = service.process_batch(images)
    assert len(result) > 0

# GUI tests: PySide6 ウィジェット
@pytest.mark.gui
def test_widget_interaction(qtbot):
    widget = ThumbnailWidget()
    qtbot.addWidget(widget)
    assert widget.isVisible()

実行コマンド

# 全テスト
uv run pytest

# カテゴリ別
uv run pytest -m unit
uv run pytest -m integration
uv run pytest -m gui

# カバレッジ付き
uv run pytest --cov=src --cov-report=html

1. Unit Test パターン

Repository Test

import pytest
from src.lorairo.database.db_core import create_test_engine
from src.lorairo.database.db_repository import ImageRepository
from src.lorairo.database.schema import Image
from sqlalchemy.orm import scoped_session, sessionmaker

@pytest.fixture
def test_db_engine():
    """テスト用DBエンジン"""
    return create_test_engine()

@pytest.fixture
def test_repository(test_db_engine):
    """テスト用リポジトリ"""
    session_factory = scoped_session(sessionmaker(bind=test_db_engine))
    repo = ImageRepository(session_factory)
    yield repo
    session_factory.remove()

@pytest.mark.unit
def test_add_image(test_repository):
    """画像追加テスト"""
    image = Image(path="/​test/​image.jpg", phash="abc123")
    result = test_repository.add(image)

    assert result.id is not None
    assert result.path == "/​test/​image.jpg"
    assert result.phash == "abc123"

@pytest.mark.unit
def test_get_by_id(test_repository):
    """ID検索テスト"""
    # Arrange
    image = Image(path="/​test/​img.jpg", phash="xyz")
    added = test_repository.add(image)

    # Act
    result = test_repository.get_by_id(added.id)

    # Assert
    assert result is not None
    assert result.id == added.id

Service Test (Mock使用)

from unittest.mock import Mock, patch
from src.lorairo.services.image_processing_service import ImageProcessingService

@pytest.fixture
def mock_repository():
    """モックリポジトリ"""
    repo = Mock(spec=ImageRepository)
    repo.get_all.return_value = [
        Image(id=1, path="/​img1.jpg"),
        Image(id=2, path="/​img2.jpg"),
    ]
    return repo

@pytest.mark.unit
def test_process_batch(mock_repository):
    """バッチ処理テスト"""
    service = ImageProcessingService(mock_repository)

    result = service.process_batch(["/​img1.jpg", "/​img2.jpg"])

    assert len(result) == 2
    mock_repository.add.assert_called()

2. Integration Test パターン

@pytest.mark.integration
def test_full_workflow(test_repository):
    """完全ワークフローテスト"""
    # 1. データ準備
    images = [
        Image(path=f"/​img{i}.jpg", phash=f"hash{i}")
        for i in range(5)
    ]

    # 2. 追加
    added = test_repository.batch_add(images)
    assert len(added) == 5

    # 3. 検索
    criteria = SearchCriteria(min_score=0.5)
    results = test_repository.search(criteria)
    assert isinstance(results, list)

    # 4. 更新
    results[0].score = 0.9
    updated = test_repository.update(results[0])
    assert updated.score == 0.9

    # 5. 削除
    deleted = test_repository.delete(results[0].id)
    assert deleted is True

3. GUI Test パターン (pytest-qt)

Widget Test

from PySide6.QtWidgets import QApplication
from PySide6.QtCore import Qt
from src.lorairo.gui.widgets.thumbnail_widget import ThumbnailWidget

@pytest.fixture
def app(qtbot):
    """Qt application"""
    return QApplication.instance() or QApplication([])

@pytest.fixture
def thumbnail_widget(qtbot):
    """Thumbnail widget fixture"""
    widget = ThumbnailWidget()
    qtbot.addWidget(widget)
    return widget

@pytest.mark.gui
def test_widget_initialization(thumbnail_widget):
    """Widget初期化テスト"""
    assert thumbnail_widget.isVisible()
    assert thumbnail_widget.windowTitle() == "Thumbnails"

@pytest.mark.gui
def test_signal_emission(qtbot, thumbnail_widget):
    """Signal発火テスト"""
    with qtbot.waitSignal(
        thumbnail_widget.image_selected,
        timeout=1000
    ) as blocker:
        # Signal発火アクション
        thumbnail_widget.select_image(0)

    # Signal引数確認
    assert blocker.args[0] == "/​path/​to/​image.jpg"

@pytest.mark.gui
def test_button_click(qtbot, thumbnail_widget):
    """ボタンクリックテスト"""
    # ボタンクリックシミュレーション
    qtbot.mouseClick(
        thumbnail_widget._ui.loadButton,
        Qt.LeftButton
    )

    # 結果確認
    assert thumbnail_widget._images_loaded is True

@pytest.mark.gui
def test_text_input(qtbot, thumbnail_widget):
    """テキスト入力テスト"""
    # テキスト入力
    qtbot.keyClicks(thumbnail_widget._ui.searchField, "test query")

    # 入力値確認
    assert thumbnail_widget._ui.searchField.text() == "test query"

Widget間通信テスト

@pytest.mark.gui
def test_widget_communication(qtbot):
    """Widget間通信テスト"""
    thumbnail = ThumbnailWidget()
    details = ImageDetailsWidget()

    qtbot.addWidget(thumbnail)
    qtbot.addWidget(details)

    # 直接接続
    details.connect_to_thumbnail_widget(thumbnail)

    # Signal発火とSlot実行確認
    with qtbot.waitSignal(thumbnail.image_metadata_selected):
        thumbnail.select_image(0)

    # 結果確認
    assert details.current_image_path == "/​img.jpg"

4. Fixture パターン

共通Fixture

# conftest.py
import pytest
from pathlib import Path

@pytest.fixture(scope="session")
def test_data_dir():
    """テストデータディレクトリ"""
    return Path(__file__).parent / "resources"

@pytest.fixture
def sample_image(test_data_dir):
    """サンプル画像"""
    return test_data_dir / "sample.jpg"

@pytest.fixture
def mock_config():
    """モック設定"""
    return {
        "database_dir": "/​tmp/​test_db",
        "max_workers": 4,
    }

@pytest.fixture(autouse=True)
def reset_state():
    """各テスト前後で状態リセット"""
    # Setup
    yield
    # Teardown
    # 必要なクリーンアップ処理

パラメータ化Fixture

@pytest.fixture(params=[1, 5, 10])
def batch_size(request):
    """異なるバッチサイズでテスト"""
    return request.param

def test_batch_processing(batch_size):
    """バッチサイズごとのテスト"""
    result = process_batch(range(batch_size))
    assert len(result) == batch_size

ベストプラクティス

DO ✅

  • AAA pattern: Arrange, Act, Assert で構造化
  • 1 test, 1 assertion: 可能な限り単一のアサート
  • Fixture活用: setup/​teardownは fixture で
  • pytest markers: 適切なマーカー付与
  • カバレッジ75%+: 最低75%のカバレッジ維持

DON'T ❌

  • 依存順序: テスト間の依存関係禁止
  • 外部依存: 外部API呼び出しはモック
  • ハードコードパス: テストデータはtests/​resources/
  • print デバッグ: logger や assert メッセージ使用
  • 長時間テスト: ユニットテストは1秒以内

テストカバレッジ要件

# カバレッジレポート生成
uv run pytest --cov=src --cov-report=html

# カバレッジ確認
# htmlcov/​index.html をブラウザで開く

# 最低カバレッジ: 75%
# 目標: ユニット 90%+, 統合 80%+, GUI 70%+

ファイル配置

tests/
├── conftest.py              # 共通fixture
├── resources/               # テストデータ
│   ├── sample.jpg
│   └── test_config.toml
├── database/                # DB tests
│   ├── test_db_repository.py
│   └── test_db_manager.py
├── services/                # Service tests
│   └── test_image_processing_service.py
└── gui/                     # GUI tests
    ├── widgets/
    │   └── test_thumbnail_widget.py
    └── window/
        └── test_main_window.py

参考リソース

More Productivity & Planning skills

brainstorming logo
Productivity & Planning

brainstorming

Structured design dialogue that validates ideas before implementation begins.

295.4K 385.7K
View
ui-ux-pro-max logo
Productivity & Planning

ui-ux-pro-max

Comprehensive design intelligence for web and mobile UI/UX across 10 technology stacks.

133.1K 383.9K
View
writing-plans logo
Productivity & Planning

writing-plans

Comprehensive implementation plans for multi-step tasks, breaking down specs into bite-sized, testable steps.

295.4K 268K
View
using-superpowers logo
Productivity & Planning

using-superpowers

Introduction to the obra skills system with mandatory skill invocation rules and best practices.

295.4K 259.8K
View
executing-plans logo
Productivity & Planning

executing-plans

Execute a written implementation plan with critical review and task checkpoints.

295.4K 229.1K
View
dispatching-parallel-agents logo
Productivity & Planning

dispatching-parallel-agents

Delegate independent tasks to specialized agents working concurrently with isolated context.

295.4K 206.3K
View
using-git-worktrees logo
Productivity & Planning

using-git-worktrees

Isolated git worktrees with smart directory selection and safety verification.

295.4K 205.2K
View
webapp-testing logo
Productivity & Planning

webapp-testing

Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

179.7K 170.6K
View
content-strategy logo
Productivity & Planning

content-strategy

Plan searchable and shareable content that drives traffic, builds authority, and generates leads.

53.3K 150.9K
View
repo-intake-and-plan logo
Productivity & Planning

repo-intake-and-plan

README-first repository scanner that extracts commands and classifies reproduction candidates without executing them.

497 139.6K
View
marketing-ideas logo
Productivity & Planning

marketing-ideas

Brainstorm and prioritize marketing strategies tailored to your SaaS stage, budget, and goals.

53.3K 137.2K
View
site-architecture logo
Productivity & Planning

site-architecture

Plan and optimize your website's page hierarchy, navigation, URL structure, and internal linking.

53.3K 112.8K
View

Productivity AI tools

Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View
SaveDay logo
Productivity

SaveDay

Capture, organize, and utilize your knowledge effortlessly.

Free
View
A
Productivity

Any Summary

Instant Summaries of Audio & Video Interviews with AnySummary

Freemium
View
M
Productivity

Map This

Transform PDFs into engaging mind maps.

Freemium
View
ChatPDF logo
Productivity

ChatPDF

Chat with any PDF instantly

Free
View
I
Productivity

intellisay

Create an optimal daily plan using your voice

Paid
View
A
Productivity

Aurora AI

A productivity platform to centralize organizational knowledge and workflows with contextual AI assistance.

Paid
View
AskYourPDF logo
Productivity

AskYourPDF

AskYourPDF Pricing Plans: Tailored to Your Needs

Free
View