あなたのテストコードは間違っている 〜TestDataFactory信仰からの脱却〜

# はじめに
Salesforceでテストコードを書く際に、次のようなコードを書いていませんか？
```Apex
@isTest
public class SampleTest {
  @isTest(seeAllData=true)
  static void testSomething() {
    Account acc = TestDataFactory.createAccount();
    // ...中略...
    Assert.areEqual('Test', acc.Name);
  }
}
```
このようなコードで、テスト対象となるクラスのコードカバレッジが75%以上になったのでリリースOK！としていないでしょうか？
確かにこれでリリース要件は満たしますが、実際には
- `seeAllData=true`の乱用
- TestDataFactoryによる共通化
- その裏でSOQLを大量発行

という問題が積み重なり、後から修正・追加をしようとした際にあなたを苦しめることになります。

# ❌ TestDataFactoryの本質的な欠陥
TestDataFactoryや静的リソースを使ったテストデータの準備はSalesforceの公式でもベストプラクティスとして紹介されているため「これが最も良い方法だ」と思い込んでしまいます。
しかし、TestDataFactoryには次のような問題点が存在します。
### 1. 実行時間が長い
TestDataFactoryはテストのたびにデータベースへレコードを挿入します。また、insertのTriggerがある場合はそこでまた処理が走り、内容によってはSELECTの大量発行なども起きうるでしょう。
そうなった時に、**ユニットテストの実行時間が長くなり**次の問題が発生します。
1. テスト→コード修正→テスト→コード修正・・・・というサイクルが回りづらくなる
1. 日本ではあまり普及していませんが、SalesforceDXを導入しようとした時により良い品質を求める際に必要な「全テスト実施」に時間がかかりすぎて現実的ではなくなる
### 2. 全てのテストケースを満たすことができない
本来、ユニットテストは個別の振る舞いに焦点を当てるべきです。
しかしFactoryは「共通の初期化処理」をまとめようとしすぎて、

> 「このテストだけAフィールドが必要」

> 「こっちはBオブジェクトが関連付いていないとダメ」

のように、テストケース間ごとに差異が生じがち。

結果、Factoryがこれらの差異を吸収するために**巨大な神クラスへ進化**し、追加改修やメンテナンスが困難になります。
- 条件分岐だらけの巨大なクラスになる
- ユニットテストの大部分を満たせるような巨大なデータセットになる
- 必要なデータをそれぞれ作成できるようなメソッドが沢山ある巨大なクラスになる

# 🤔 なぜ公式はTestDataFactoryを推奨するのか？

確かにSalesforceの公式ドキュメントではTestDataFactoryの利用が推奨されています。
しかし、それは初心者向けの「とっかかり」としてのベストプラクティスであって、
以下のような点では現実の開発・保守に不適合です：

- 現代の開発ではSFDXやCI/CDの導入が前提になっており、実行時間とデータ依存の影響は無視できない
- 複雑なドメインロジックに対応しようとすると、TestDataFactoryは肥大化・複雑化・ブラックボックス化する
- 「共通化」は一見効率的に見えて、実際はユニットテストの意図の不明瞭化とテスト間干渉を招くことが多い

そのため、公式の示すスタイルは出発点としては良いですが、
スケールするプロジェクトでは限界が早く訪れます。

# ✅ 解決策：ユニットテストは“振る舞いの検証”に集中せよ
私が提案するのは、Query Delegation Pattern + Apex Eloquent を使用した次の設計です。

### 1. データベースを使用しないユニットテスト
クエリの**構築と実行を分離**(Query Delegation Pattern)し、**実行部分を抽象に依存**(Apex Eloquent)することでSOQLを発行することなくテストが可能になるため、テストデータ作成に関わる様々な問題に頭を悩ます必要がなくなります。

```apex
@isTest(seeAllData=false)
public with sharing class OppNameUpdatorUsingApexEloquent_T {

  @isTest(seeAllData=false)
  public static void testExecute() {
    // create test Data
    Opportunity mockOpp = new Opportunity();
    mockOpp.Id = '006000000000001';
    mockOpp.Name = 'Test Opportunity';

    // create MockRepository
    MockRepository mockRepository = new MockRepository(mockOpp);

    // create instance of the class
    OppNameUpdatorUsingApexEloquent updator = new OppNameUpdatorUsingApexEloquent(mockOpp.Id, mockRepository);

    // execute the method
    Opportunity updatedOpp = updator.execute();

    // verify the result
    String expectedName = 'Updated Opportunity Name';
  }
}
```

### 2. 結合テストは“代表的な組み合わせ”に絞る
十分なユニットテストによって品質が保証されたクラスを束ねて実行するような司令塔のようなクラスでは、結合テストによってその品質を保証します。
ただしこの場合は、部品となるクラスはすでにユニットテストにより品質が問題ないことを保証されているため、細かい条件分岐をテストする必要はありません。
- データベースを使用した代表ケースのみ
- 想定どおりの一連の処理が「落ちない」ことを確認する

これにより、**単体テストでの網羅 + 結合テストでの動作保証**という役割分担ができます。

# 🔥 まとめ：「正しいテスト」は何か？

- Assert.isTrue(true) や seeAllData=true は原則NG
- TestDataFactoryはCI/CD時代には大きな負債になる
- ユニットテストは本番ロジックの“振る舞い”に集中する
- そのために、Query Delegation patternとApex Eloquentの導入は極めて有効

# 📣 宣伝：Apex Eloquent + クエリ委譲パターンについて

詳しくは別記事：
「取得」と「実行」を分離せよ！Query Delegation Patternで見直すデータアクセスの責務

👉 https://qiita.com/krile136/items/235c543eff547a4cfe50