Apex で CSV を読み込んでテストデータを作成する方法


テストデータを **CSV（静的データ）** から読み込んで作成する方法を、**ポケモン一覧、わざ一覧、せいかく一覧** の CSV を例に解説します。  

**今回の設定:**  
- **ポケモン（親データ）**: `Pokemon__c` オブジェクト  
- **わざ（子データ）**: `Move__c` オブジェクト（`Pokemon__c` と関連）  
- **せいかく（子データ）**: `Nature__c` オブジェクト（`Pokemon__c` と関連）

---

## **1. CSV ファイルの準備**
### **(1) ポケモン一覧 (`pokemon.csv`)**
```csv
Name,Type,HP,Attack,Defense
Pikachu,Electric,35,55,40
Charmander,Fire,39,52,43
Bulbasaur,Grass,45,49,49
Squirtle,Water,44,48,65
```

### **(2) わざ一覧 (`moves.csv`)**
```csv
Pokemon,Move,Power,Type
Pikachu,Thunderbolt,90,Electric
Charmander,Flamethrower,90,Fire
Bulbasaur,Razor Leaf,55,Grass
Squirtle,Water Gun,40,Water
```

### **(3) せいかく一覧 (`natures.csv`)**
```csv
Pokemon,Nature,AttackMod,DefenseMod
Pikachu,Timid,0.9,1.0
Charmander,Adamant,1.1,0.9
Bulbasaur,Modest,0.9,1.1
Squirtle,Relaxed,1.0,1.1
```

---

## **2. Apex で CSV を読み込む方法**
Apex では **`StaticResource`** を使って CSV を保存し、それをテストクラスで読み込んでデータを作成できます。

### **(1) スタティックリソースに CSV を保存**
1. **[設定] → [カスタムコード] → [静的リソース]**
2. **「新規」ボタンを押して CSV をアップロード**
   - `pokemon.csv`
   - `moves.csv`
   - `natures.csv`

---

## **3. CSV を読み込んでテストデータを作成する Apex コード**
### **(1) ヘルパークラス（CSV 読み込み用）**
まず、CSV を読み込んで **リスト形式に変換するヘルパークラス** を作成します。

```apex
public class CSVParser {
    public static List<Map<String, String>> parseCSV(String staticResourceName) {
        List<Map<String, String>> records = new List<Map<String, String>>();
        try {
            // スタティックリソースから CSV データを取得
            StaticResource sr = [SELECT Body FROM StaticResource WHERE Name = :staticResourceName];
            String csvData = sr.Body.toString();

            // 各行をリスト化
            List<String> lines = csvData.split('\n');
            List<String> headers = lines[0].split(',');

            // データ部分をマップに格納
            for (Integer i = 1; i < lines.size(); i++) {
                List<String> values = lines[i].split(',');
                Map<String, String> record = new Map<String, String>();
                for (Integer j = 0; j < headers.size(); j++) {
                    record.put(headers[j].trim(), values[j].trim());
                }
                records.add(record);
            }
        } catch (Exception e) {
            System.debug('CSV 読み込みエラー: ' + e.getMessage());
        }
        return records;
    }
}
```

---

### **(2) テストデータを作成するファクトリクラス**
CSV からデータを読み込み、オブジェクトを作成する `TestDataFactory` クラスを作ります。

```apex
@isTest
public class TestDataFactory {
    
    public static List<Pokemon__c> createPokemonData() {
        List<Pokemon__c> pokemonList = new List<Pokemon__c>();
        List<Map<String, String>> records = CSVParser.parseCSV('pokemon');

        for (Map<String, String> record : records) {
            Pokemon__c p = new Pokemon__c(
                Name = record.get('Name'),
                Type__c = record.get('Type'),
                HP__c = Integer.valueOf(record.get('HP')),
                Attack__c = Integer.valueOf(record.get('Attack')),
                Defense__c = Integer.valueOf(record.get('Defense'))
            );
            pokemonList.add(p);
        }
        insert pokemonList;
        return pokemonList;
    }

    public static void createMoveData() {
        List<Map<String, String>> records = CSVParser.parseCSV('moves');
        List<Move__c> moveList = new List<Move__c>();

        for (Map<String, String> record : records) {
            Pokemon__c pokemon = [SELECT Id FROM Pokemon__c WHERE Name = :record.get('Pokemon') LIMIT 1];
            Move__c move = new Move__c(
                Name = record.get('Move'),
                Power__c = Integer.valueOf(record.get('Power')),
                Type__c = record.get('Type'),
                Pokemon__c = pokemon.Id
            );
            moveList.add(move);
        }
        insert moveList;
    }

    public static void createNatureData() {
        List<Map<String, String>> records = CSVParser.parseCSV('natures');
        List<Nature__c> natureList = new List<Nature__c>();

        for (Map<String, String> record : records) {
            Pokemon__c pokemon = [SELECT Id FROM Pokemon__c WHERE Name = :record.get('Pokemon') LIMIT 1];
            Nature__c nature = new Nature__c(
                Name = record.get('Nature'),
                Attack_Modifier__c = Decimal.valueOf(record.get('AttackMod')),
                Defense_Modifier__c = Decimal.valueOf(record.get('DefenseMod')),
                Pokemon__c = pokemon.Id
            );
            natureList.add(nature);
        }
        insert natureList;
    }
}
```

---

### **(3) テストクラス**
テストクラスで `TestDataFactory` を使い、データを作成して検証します。

```apex
@isTest
private class PokemonTest {
    
    @TestSetup
    static void setupTestData() {
        TestDataFactory.createPokemonData();
        TestDataFactory.createMoveData();
        TestDataFactory.createNatureData();
    }

    @isTest
    static void testPokemonData() {
        List<Pokemon__c> pokemons = [SELECT Id FROM Pokemon__c];
        System.assertEquals(4, pokemons.size());
    }

    @isTest
    static void testMoveData() {
        List<Move__c> moves = [SELECT Id FROM Move__c];
        System.assertEquals(4, moves.size());
    }

    @isTest
    static void testNatureData() {
        List<Nature__c> natures = [SELECT Id FROM Nature__c];
        System.assertEquals(4, natures.size());
    }
}
```

---

## **まとめ**
✅ **CSV を `StaticResource` に保存**  
✅ **`CSVParser` クラスで CSV をリスト形式に変換**  
✅ **`TestDataFactory` でデータ作成**  
✅ **テストクラスで `@TestSetup` を使いデータを準備**  

これにより、大量のテストデータを **外部 CSV から簡単に作成** できます！  
実際のプロジェクトでも、商品データや顧客データなどを CSV から読み込んでテストを行う際に役立ちます！🚀