エージェント生成コードのためのPytest:実践的な具体的テスト戦略
エージェントがテストを作成する際、意図と正確性が重要です。明確なテストレベル、推奨パターン、明示的なアンチパターンを定義することで、自動化とともに拡張可能な高速で信頼性の高いPytestスイートを生成する構造を提供します。
キーポイント
AIエージェントによるテスト生成では、意図の明確化と正しさが同等に重要であり、構造化されたテスト戦略が必要
テスト生成は限定されたサブエージェントとして分離し、コンテキストを意図的に管理することで、テスト対象コードの誤修正を防止
リポジトリ全体のテスト戦略として、テストレベル、推奨パターン、禁止パターンを明確に定義し、自動化スケーリングに対応
テストは「スキル」ベースで設計され、各タスクは独立したコンテキストで実行され、読みやすく意図的で決定論的なテストを生成
影響分析・編集コメントを表示
影響分析
この記事は、AIによるコード生成が一般的になる中で、特にテストコードの自動生成における実践的なガバナンス手法を提示している。Dagsterの実践例は、AI支援開発における品質維持の具体的なフレームワークとして、他の組織にも応用可能な知見を提供する。
編集コメント
AIが生成するコードの「尊厳」を保ちつつ、テストまで自動化する実践的なノウハウ。プロダクション環境でのAI活用において、品質担保の方法論が具体化されてきた証左と言える。
Compass をご紹介 — Slack 向けの Dagster 新 AI データアナリストです。質問を即座に信頼できるインサイトに変換します。今すぐ Compass をお試しください → データアセットが最も得意とするところを、データアセットがどのように連携して機能するかを描いたアニメーション付きナレーションストーリーで発見しましょう。今すぐ視聴 →
Dagster の利用を開始 | サインイン
エージェントがテストコードを作成する際、正しさと同様に意図も重要です。明確なテストレベル、推奨されるパターン、そして明示的なアンチパターンを定義することで、自動化に合わせてスケーラブルかつ高速で信頼性の高い Pytest スイートを生成するために必要な構造をエージェントに提供します。
以前の投稿では、エージェントによって生成された Python コードが常に「品格ある」ものとなるよう、私たちが内部で使用しているいくつかのスタイル上の選択について議論しました。スタイル、構造、そして Python の慣習的な書き方をカバーするこれらのルールは、コードの多くが機械支援によって作成される場合でも、一貫して高品質なコードベースを維持するのに役立ちます。
しかし、支援を受けながらコードを作成する場合、テストについてもエージェントに同じ基準を適用する必要があります。実際には、微妙なエラーや長期的なメンテナンス上の問題を引き起こすことなく、エージェントに対してテストの設計と記述方法をどのように指示するかを明確にする必要があります。
これには、「良いテスト」とはどのようなものかだけでなく、いつテストを書くべきか、異なる状況でどの種類のテストが適切か、そしてどのパターンが禁止されるかを定義する、リポジトリ全体にわたるテスト戦略が必要です。
つまり、テストの書き方を定義するルールとロジックを提供し、その決定を推論に委ねてはならないのです。
私たちのテスト戦略はスキルを中心に設計されています。これらのスキルの詳細の多くは、いくつかの微妙な変更を加えることで、あらゆるリポジトリに適用可能です。しかし、実際のテスト戦略に入る前に、これらのテストがワークフロー内でどのように実行されるかについて議論しておくことが重要です。
テスト作成エージェントは、アプリケーションコードを生成するエージェントと同じ権限や文脈を使用しません。テスト生成は、隔離されたコンテキストウィンドウ内で意図的に制限された役割を持つサブエージェントとして実行されます。テスト作業をサブエージェントに限定することで、エージェントがテストの失敗を「修正」するために、テスト対象のコードを微妙に調整するという一般的な失敗モードを防ぎます。
そのサブエージェント内では、各スキルは特定の関数に対するカバレッジを追加する、報告されたバグを再現する、または明確化のために既存のテストをリファクタリングするなど、狭いタスクを表します。要求が制限されたスキルとして表現できない場合、それは通常、自動化されたテストパスには属しません。
最後に、私たちは文脈を非常に意図的に管理しています。テストサブエージェントはタスク固有のコンテキストで実行され、実行間を通じて履歴を蓄積しません。これにより、推測的なテストや、過去の失敗への偶発的な依存、非推奨の動作に基づくアサーションが回避されます。各呼び出しは単独で成立可能であり、可読性があり、意図的かつ決定論的なテストを生成する必要があります。
私たちは単純なワークフローから始めます。src ディレクトリの下に導入された新しいロジックに対しては、必ずテストを作成すべきです。エージェントが現在の作業セッションで実際に実装されているコードのみに対してテストを書くべきであることを明確にしています。
エージェントにテスト対象とする範囲を限定することで、ノイズを減らし、テストがコードベースに対する実際かつ意図的な変更を追跡するように保証します。
テスト可能な新規コードの範囲を制限した後、新機能の開発のためのコードとバグ修正のためのコードを区別し始めます。
バグ修正は、より定型的な手順に従います:
- バグを再現する失敗するテストを書く。
- テストを実行し、それが現在成功することを確認する。
- 回帰テストとしてそのテストを残す。
新機能については、テスト駆動開発(TDD)が推奨されます。適切なテストは機能と共に含まれることを期待しますが、どのテストを書くか、またどのレベルで書くかという具体的な詳細は、やや洗練されたものになります。
リポジトリの文脈の一部として、私たちは明示的なテストレベルをいくつか定義しています。各レベルについて、その目的と、全体のテストスイートにおいて占めるべきおおよその割合を説明します。これにより、エージェントに対して、ほとんどのテストがどこに存在すべきかという強力な事前知識(prior)を与えます。
例えば、あるコードベースでは、テスト用に特別に構築されたインフラのフェイク実装に対して、テストの大多数が記述されています。リファクタリング時に脆くなりやすく、パフォーマンスや安全性の問題を引き起こす可能性があるため、モックを過度に使用するアプローチよりも、この手法を好みます。
私たちのテストレベルを表したテーブルは、ビジネスロジックテスト(レベル 4)がテストコードベースの大多数を占めるべきであることをエージェントに指示することで、この優先順位を反映しています。
この表は、分布を明示することで意図を符号化し、新しいテストをどこに配置すべきかをエージェントにシグナルを送ります。
各レベルのルーティングは、testing-strategy.md スキル内のロジックによって処理され、ここでは特定のテスト戦略がいつ、なぜ選択されるべきかに関する詳細を含んでいます:
レイヤー 4: フェイクに対するビジネスロジックテスト(多数派)
目的:高速なインメモリフェイクを使用してアプリケーションロジックを徹底的にテストする。
場所:tests/unit/services/, tests/unit/, tests/commands/
いつ記述するか:すべての機能とバグ修正に対して。これがデフォルトのテストレイヤーです。
理由:高速、信頼性が高く、容易にデ
原文を表示
Meet Compass — Dagster’s new AI data analyst for Slack. Turn questions into trusted insights, instantly. Try Compass now →Discover What assets do best, an animated, narrated story about how data assets work together. Watch now →
Try Dagster+Sign InWhen agents write tests, intent matters as much as correctness. By defining clear testing levels, preferred patterns, and explicit anti-patterns, we give agents the structure they need to produce fast, reliable Pytest suites that scale with automation.
In a previous post, we discussed some of the stylistic choices we use internally to ensure that Python code generated by our agents remains “dignified.” These rules, covering style, structure, and idiomatic Python, help us maintain a consistently high-quality codebase even when much of the code is machine-assisted.
However, when we write code with assistance, our agents must also be held to the same standard for tests. In practice, this means being explicit about how we instruct our agents to design and write tests without introducing subtle errors or long-term maintenance issues.
This requires repository-wide testing strategies that define not just what “good tests” look like, but also when tests should be written, what kinds of tests are appropriate in different situations, and which patterns are disallowed.
In other words, we need to supply the rules and logic that define how tests should be written, not leave those decisions up to inference.
Our testing strategy is designed around skills. Most of the details for these skills can apply to any repo (with some slight changes). But before getting into our actual testing strategy, it is good to discuss how these tests run within our workflows.
Test-writing agents do not use the same authority or context as agents that produce application code. Test generation runs as sub-agents with a deliberately constrained role within an isolated context window. Constraining test work to a sub-agent prevents the common failure mode where an agent “fixes” a failing test by subtly adjusting the code under test.
Within that sub-agent, each skill represents a narrow task, adding coverage for a specific function, reproducing a reported bug, or refactoring an existing test for clarity. If a request can’t be expressed as a bounded skill, it usually doesn’t belong in an automated test pass.
Finally, we manage context very intentionally. Test sub-agents run with task-specific context and do not accumulate history across runs. This avoids speculative tests, accidental dependency on prior failures, and assertions based on deprecated behavior. Each invocation should be able to stand alone, producing tests that are readable, intentional, and deterministic.
We start with simple workflows. Tests should be written for any new logic introduced under the src directory. We are explicit that agents should only write tests for the code actively being implemented in the current work session.
By narrowing the scope of what an agent is allowed to test, we reduce noise and ensure that tests track real, intentional changes to the codebase.
After limiting the scope of what qualifies as new testable code, we begin to distinguish between code for new feature development vs bug fixes.
Bug fixes, follow a more routine order of operations:
Write a failing test that reproduces the bug.
Run the test and confirm that it now passes.
Leave the test in place as a regression test.
For new features, Test Driven Development is encouraged. We expect appropriate tests to be included alongside the feature, though the specifics of which tests to write, and at what level are slightly more sophisticated.
As part of our repository context, we define a number of explicit testing levels. For each level, we describe its purpose and the rough proportion of the overall test suite it should represent. This gives agents a strong prior for where most tests should live.
For example, in one of our codebase, the majority of tests are written against a fake implementation of infrastructure, built specifically for testing. We prefer this approach over heavy use of mocks because they tend to be brittle upon refactoring and can introduce performance and safety issues.
The table for our testing levels reflects this preference by instructing the agent that business logic tests (level 4) should represent the majority of our testing codebase.
This table encodes intent by making the distribution explicit and we signal to the agent where new tests should land.
The routing for each level is handled by logic within the testing-strategy.md skill, were we include include details on when and why certain testing strategies should be chosen:
Layer 4: Business Logic Tests over Fakes (MAJORITY) Purpose: Test application logic extensively with fast in-memory fakes. Location: tests/unit/services/, tests/unit/, tests/commands/ When to write: For EVERY feature and bug fix. This is the default testing layer. Why: Fast, reliable, easy to de
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み