はじめに
今回は spring-demo-project を使って、失敗したテストログを「UI からコンテキストを追加する」でAI Chat に渡し、原因の説明と修正方針を出してもらう流れを試します。
テストが落ちたとき、エラーログだけを見ても原因がすぐにわからないことがあります。
Spring Boot のように複数のサービスクラスが関係するコードでは、
- テストの期待値が間違っているのか
- 実装の条件分岐が間違っているのか
- そもそも仕様の読み取りが違うのか
を切り分けると時間がかかります。
JetBrains の AI Chat では、IDE の Run ツールウィンドウや Terminal など、UI 上に表示されている内容をそのままコンテキストとして追加できます。
実際にやってみた
今回使うのは、注文処理を題材にしたデモ Spring Boot プロジェクトです。
spring-demo-project/
├── pom.xml
└── src/
├── main/java/com/example/order/
│ ├── Order.java
│ ├── OrderService.java
│ ├── PaymentService.java
│ └── UserService.java
└── test/java/com/example/order/
└── PaymentServiceTest.java
pom.xml では Spring Boot 3.2.0 と Java 17 を使っています。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<properties>
<java.version>17</java.version>
</properties>
題材にするのは PaymentService です。
@Service
public class PaymentService {
private final OrderService orderService;
private final UserService userService;
@Autowired
public PaymentService(OrderService orderService, UserService userService) {
this.orderService = orderService;
this.userService = userService;
}
@Transactional
public void processPayment(Long orderId) {
Order order = orderService.findOrder(orderId);
userService.updateUserBalance(order.getUserId(), order.getAmount().negate());
order.markPaid();
}
@Transactional
public void refund(Long orderId) {
Order order = orderService.findOrder(orderId);
userService.updateUserBalance(order.getUserId(), order.getAmount());
order.markRefunded();
}
public boolean canRefund(Order order) {
return order.getStatus() == Order.Status.PAID
|| order.getStatus() == Order.Status.SHIPPED;
}
}
canRefund() は、注文ステータスが PAID または SHIPPED の場合に true を返します。
失敗するテストを用意する
ここでは、失敗するテストを追加します。
@Test
@DisplayName("出荷済み注文は返金不可")
void canRefund_returnsFalse_whenOrderIsShipped() {
// given
Order order = new Order(300L, 1L, new BigDecimal("3000"));
order.markShipped();
// when
boolean result = paymentService.canRefund(order);
// then
assertThat(result).isFalse();
}
このテストは、SHIPPED の注文は返金できないはずだ、というふうに書いています。
しかし実装では、SHIPPED は返金可能ですので、テストを実行すると失敗します。
ここでは、ログをコピーして Chat に貼るのではなく、Run ツールウィンドウ UI からそのままコンテキストとして追加することです
AI Chat に Run ツールウィンドウを渡す
AI Assistant の Chat を開きます。
次に、Chat 入力欄の近くにある 添付の追加 から、UI からコンテキストを追加する を選びます。
その後、失敗ログが表示されている Run ツールウィンドウを選択します。
今回は、ログだけではなく PaymentService.java も一緒に見てほしいので、ファイルもコンテキストに追加しました。
そして次のようにプロンプトしました。
添付した Run ツールウィンドウのテスト失敗ログと PaymentService.java を見て、
なぜ PaymentServiceTest が失敗しているのか説明してください。
実装とテストのどちらを直すべきか判断し、最小限の修正案を示してください。
単に「直して」ではなく、失敗ログを見てほしい、関連する実装ファイルも見てほしい、実装とテストのどちらを直すべきか判断してほしい、最小限の修正案がほしいと明示することです。
これにより、AI Assistant は「エラー文の解説」だけではなく、仕様とコードの関係まで踏み込んで整理しやすくなります。
AI Assistant の回答
実際に Run ツールウィンドウの失敗ログと PaymentService.java を添付して質問すると、AI Assistant は失敗原因を次のように整理しました。
今回の失敗は、例外や Mockito の設定ミスではなく、
SHIPPED の返金可否に対する実装とテストの期待値の不一致です。
このケースでは、原因はテスト側の期待値です。
PaymentService.canRefund() は次の条件で true を返します。
return order.getStatus() == Order.Status.PAID
|| order.getStatus() == Order.Status.SHIPPED;
つまり、SHIPPED は返金可能なステータスとして扱われています。
一方、追加したテストでは order.markShipped() の後に assertThat(result).isFalse() と書いています。
order.markShipped();
boolean result = paymentService.canRefund(order);
assertThat(result).isFalse();
そのため、実装が true を返し、テストは false を期待しているので失敗します。
AI Assistant は、修正方針についても「実装を直すか、テストを直すかは仕様次第」と回答していました。
PaymentService.canRefund() は PAID または SHIPPED の場合に true を返す実装です。
今回のテストは SHIPPED の注文に対して false を期待しているため、実装とテストの期待値が矛盾しています。
仕様として「出荷済み注文も返金可能」が正しいなら、テスト名と期待値を修正します。
仕様として「出荷済み注文は返金不可」が正しいなら、canRefund() の条件から SHIPPED を外します。
単に Expected false / Actual true を説明するだけではなく、ログと実装を結びつけて、仕様判断が必要なポイントまで整理してくれました。
修正案 1: 実装が正しい場合
SHIPPED の注文も返金可能、という仕様が正しいなら、テストを直します。
@Test
@DisplayName("出荷済み注文は返金可能")
void canRefund_returnsTrue_whenOrderIsShipped() {
// given
Order order = new Order(300L, 1L, new BigDecimal("3000"));
order.markShipped();
// when
boolean result = paymentService.canRefund(order);
// then
assertThat(result).isTrue();
}
この修正では、実装は変更しません。
テスト名、DisplayName、期待値を実装の仕様に合わせます。
修正案 2: テストが正しい場合
逆に、仕様として「出荷済み注文は返金不可」が正しいなら、実装を直します。
public boolean canRefund(Order order) {
return order.getStatus() == Order.Status.PAID;
}
この場合は、既存の仕様を変えることになるため、影響範囲を確認する必要があります。
例えば、refund() の呼び出し元で SHIPPED の注文を返金可能として扱っている画面や API がないかを確認します。
AI Assistant には追加で、次のように聞くとよさそうです。
SHIPPED を返金不可に変更した場合の影響範囲を、
このプロジェクト内の参照箇所から確認してください。
小さなサンプルプロジェクトでも、仕様変更なのかテスト修正なのかを分けて考えることができます。
UI から追加するメリット
Run ツールウィンドウを UI から追加すると、次のような情報をまとめて渡せます。
- どのテストクラスが失敗したか
- どのテストメソッドが失敗したか
- Expected / Actual の差分
- スタックトレース
- 実行した構成や対象
手動でコピーすると、必要な行を落としたり、逆に不要なログを大量に貼ってしまいます。
UI から追加すれば、IDE 上で見ている失敗状態をそのまま AI Assistant に渡せます。
注意点
UI から追加するコンテキストには、ログに表示されている内容が含まれます。
そのため、送る前にAIに読まれたくない情報が混ざっていないかを確認してください。
また、.aiignore で除外している内容でも、UI 上に表示されているものをコンテキストとして追加すると AI Assistant に渡る可能性があります。
まとめ
JetBrains AI Assistant の UI からコンテキストを追加する を使うと、Run ツールウィンドウに表示されたテスト失敗ログを AI Chat に渡せます。
ログ、対象クラス、テストコードをまとめて渡すことで、AI Assistant に次のような調査を依頼できます。
- 失敗原因の説明
- 実装とテストのどちらを直すべきかの整理
- 最小限の修正案
- 仕様変更時の影響範囲確認
Run ツールウィンドウ、エディタ、テスト結果をそのままコンテキストとして扱えるため、JetBrains IDE と相性のよい使い方だと感じました。
ナットウシステムからのお知らせ
弊社は JetBrains 製品に関するご質問、ご相談等を受け付けております。弊社のXまたはメールでご連絡ください。
参考


