はじめに
この記事は、Stable Diffusion XL on macOS: Efficient Testing with BDD and safetensorsの記事で紹介されているBDDテストの実装例をベースに、pytest-bddの使い方を詳しく解説するものです。実装例の全コードはGitHubリポジトリで公開されています。
BDD(Behavior Driven Development)は、テスト駆動開発(TDD)から派生した開発手法で、システムの振る舞いを自然言語で記述し、それを元にテストと実装を進めていく方法です。最近、この手法がAIとの協業において効果的であることを実感しています。特にAIに対する要件の明確化や、期待する動作の指示において、その効果を強く感じています。、システムの振る舞いを自然言語で記述し、それを元にテストと実装を進めていく方法です。本記事では、Pythonで人気のテストフレームワークpytestの拡張機能であるpytest-bdd
を使って、BDDテストを実践する方法を解説します。
私は最近、機械学習モデルを使用したプロジェクトでBDDアプローチを採用し、その有用性を実感しました。特に、チーム内でのコミュニケーションや要件の明確化において、大きな効果がありました。
環境設定
まずは必要なパッケージをインストールします。
pip install pytest pytest-bdd
プロジェクト構造
BDDテストを効率的に管理するために、以下のようなプロジェクト構造を推奨します:
tests/
├── features/ # Gherkinシナリオ
│ ├── calc/ # 計算機能のfeature
│ │ ├── basic.feature
│ │ └── advanced.feature
├── step_definitions/ # ステップの実装
│ └── test_calc.py
├── fixtures/ # 共通フィクスチャー
│ └── calc.py
└── conftest.py # テスト全体の設定
この構造により、テストの管理が容易になり、コードの再利用性も高まります。
基本的な使い方
1. フィーチャーファイルの作成
まず、テスト対象の振る舞いを自然言語で記述したフィーチャーファイルを作成します。例として、簡単な計算機能のテストを考えてみましょう。
# tests/features/calc/basic.feature
Feature: 基本的な計算機能
電卓アプリケーションの基本的な計算機能をテストする
Background:
Given 計算機を準備する
Scenario: 2つの数値の加算
Given 最初の数値として5を入力する
And 2番目の数値として3を入力する
When 加算を実行する
Then 結果は8になる
Scenario Outline: 複数のパターンでの加算テスト
Given 最初の数値として<num1>を入力する
And 2番目の数値として<num2>を入力する
When 加算を実行する
Then 結果は<expected>になる
Examples:
| num1 | num2 | expected |
| 1 | 1 | 2 |
| 10 | 20 | 30 |
| -5 | 5 | 0 |
2. ステップ定義の実装
次に、フィーチャーファイルで定義したステップを実装します。
# tests/step_definitions/test_calc.py
from pytest_bdd import scenario, given, when, then, parsers
from calculator import Calculator
@scenario('calc/basic.feature', '2つの数値の加算')
def test_add():
pass
@given('計算機を準備する', target_fixture='calculator')
def calculator():
return Calculator()
@given(parsers.parse('最初の数値として{number:d}を入力する'))
def input_first_number(calculator, number):
calculator.input_first(number)
@given(parsers.parse('2番目の数値として{number:d}を入力する'))
def input_second_number(calculator, number):
calculator.input_second(number)
@when('加算を実行する')
def execute_addition(calculator):
calculator.add()
@then(parsers.parse('結果は{expected:d}になる'))
def check_result(calculator, expected):
assert calculator.result == expected
# Scenario Outline用のテスト関数
@scenario('calc/basic.feature', '複数のパターンでの加算テスト')
def test_add_multiple():
pass
3. テスト対象クラスの実装
最後に、テスト対象となる実装を作成します。
# calculator.py
class Calculator:
def __init__(self):
self.first = 0
self.second = 0
self.result = 0
def input_first(self, number):
self.first = number
def input_second(self, number):
self.second = number
def add(self):
self.result = self.first + self.second
pytest-bddの高度な使い方
パラメータ化されたステップ
複数のパターンでテストを実行したい場合、Scenario Outlineを使用します。これにより、同じシナリオを異なるデータセットで実行できます。
Scenario Outline: 様々な計算のテスト
Given 演算子として<operator>を選択する
And 最初の数値として<num1>を入力する
And 2番目の数値として<num2>を入力する
When 計算を実行する
Then 結果は<expected>になる
Examples:
| operator | num1 | num2 | expected |
| + | 5 | 3 | 8 |
| - | 10 | 4 | 6 |
| * | 2 | 6 | 12 |
フィクスチャーの活用
よく使用する前提条件は、フィクスチャーとして定義することで再利用が可能です。
# tests/fixtures/calc.py
import pytest
from calculator import Calculator
@pytest.fixture
def calculator():
return Calculator()
@pytest.fixture
def calculator_with_numbers():
calc = Calculator()
calc.input_first(10)
calc.input_second(5)
return calc
タグによるテスト管理
特定のテストだけを実行したい場合、タグを使用して管理できます。
@slow
@integration
Scenario: 大量データの計算
Given 1000個の数値を入力する
When バッチ計算を実行する
Then すべての結果が正しい
タグを指定してテストを実行:
pytest -v -k "slow and not integration"
BDDテストのベストプラクティス
1. シナリオの粒度
シナリオは以下の特徴を持つように設計します:
- 1つのシナリオで1つの振る舞いをテスト
- 理解しやすい自然な日本語で記述
- テストの意図が明確に伝わる
2. ステップの再利用
- 共通のステップは再利用可能な形で実装
- パラメータ化を活用して柔軟性を確保
- Backgroundを使用して共通の前提条件を定義
3. テストの保守性
- 適切な名前付けとコメントの活用
- モジュール化とコードの整理
- CI/CDパイプラインへの組み込み
テストレポートの活用
pytest-bddは、テスト結果を分かりやすいレポートとして出力できます。HTML形式のレポートを生成するには、pytest-html
プラグインを使用します:
pip install pytest-html
pytest --html=report.html
まとめ
pytest-bddを使用したBDDテストの導入により、特にAIとの協業において以下のメリットを感じています:
- 要件の明確化とドキュメント化
- 自然言語での記述により、AIに求める動作を明確に指示可能
- テストケースを通じて期待する動作を具体的に示せる
- 段階的な開発アプローチの実現
- AIが生成したコードの品質を確保
- 要件からテスト、実装まで一貫した流れで開発を進められる
- テストの保守性と再利用性の向上
- AIが生成したコードの品質を継続的に確認可能
- パターン化された要件は再利用が容易
BDDは単なるテスト手法ではなく、AIとの協業を効果的に進めるためのコミュニケーションツールとしても機能します。自然言語による要件定義とテストの自動化により、AIとの開発プロセスをより確実なものにできます。
参考文献
- pytest-bdd公式ドキュメント: https://pytest-bdd.readthedocs.io/
- Behavior Driven Development: https://cucumber.io/docs/bdd/
- pytest-bddとBDDによるAIとの効率的な協業アプローチ - 本記事のベースとなった実践例
著者について
現在、AIと協業したプログラミングの実践に取り組んでいるエンジニアです。特に、AIとの効果的な協業を実現するための手法として、BDDに大きな可能性を感じています。
BDDの特徴である「自然言語による要件定義」と「振る舞いの明確化」は、AIとの協業において以下のような利点があります:
- AIに対して明確な期待動作を伝えることができる
- 実装の意図と目的が明確になり、AIとのコミュニケーションが円滑になる
- テストケースを通じて、AIが生成したコードの品質を確保できる
本記事の内容や、AIとの協業におけるBDDの活用について、コメントでお気軽にご相談ください。