[Apex] 開発者コンソールのチェックポイントを利用したデバッグ方法

## チェックポイントとは
チェックポイントは開発者コンソールの機能で、Apexクラスおよびトリガのデバッグを行います。Apexコードの特定の行にチェックポイントを設定することで、行に到達した時点でのメモリやデータベースの状態を確認することができます。

一般的なデバッグの手段としては ```System.debug()``` メソッドがありますが、チェックポイントを利用したデバッグでは特定のApexコードの記述を必要としません。よって、デバッグのためにわざわざApexコードを変更する必要は無くなります。

本記事ではチェックポイントの基本的な使い方を説明します。

## 準備
- チェックポイントを使用するには、Apexログレベルを [Finer] または [Finest] に設定する必要があります。詳細は[ログレベルの設定](https://help.salesforce.com/articleView?id=code_dev_console_tab_browser_logs.htm&type=0)を参照して下さい。
- 動作確認用のサンプルコードとして、取引先レコード3件を作成するメソッドを用意します。

```java:CheckpointSample.cls
public class CheckpointSample {

    public static List<Account>createAccounts(){
        List<Account>acclist = new List<Account>();

        for(Integer i = 0; i < 3; i++){
            String accNumber = String.valueOf(i + 1);
            Account acc = new Account(
                Name = 'サンプル取引先' + accNumber,
                AccountNumber = accNumber
            );
            acclist.add(acc);
        }

        insert acclist;
        return acclist;
    }

}
```

## チェックポイント実行手順
### チェックポイントの登録
サンプルコードのデバッグを行うためのチェックポイントを登録します。

1. 開発者コンソールを開きます。　（参考:[開発者コンソールの開き方](https://help.salesforce.com/articleView?id=code_dev_console_opening.htm&type=0&language=ja)）
2. コードエディタでサンプルコードを開きます。メニューから ```File > Open > Classes > CheckpointSample ``` を選択し、Openボタンをクリックします。
3. コードの16行目にチェックポイントを登録します。行番号の左側の余白部分をクリックします。  
<img src="https://qiita-image-store.s3.amazonaws.com/0/39902/8fd7061a-50fe-dead-81a2-e2b95994dda9.png" height="60">
4. 赤いマークが付き、チェックポイントの登録が完了しました。（赤いマークをクリックすると削除されます）  
<img src="https://qiita-image-store.s3.amazonaws.com/0/39902/df194e03-cb3b-08fb-a208-93dbb55ed1c4.png" height="60">

デバッグが行われるタイミングは、厳密には**チェックポイントを登録した行が実行される直前**の時点です。今回はinsert実行後の状態を見るため、16行目（insert文の次の行）に登録しています。

後はこのまま開発者コンソールを開いた状態にしておくと、Apexコード実行時にチェックポイントに到達したタイミングで自動的にデバッグが行われ、結果が保存されていきます。
（実行および結果の確認については後で説明します）

登録したチェックポイントの一覧は、[Checkpoints]タブ > [Checkpoint Locations]リストに表示されます。
<img width="600" src="https://qiita-image-store.s3.amazonaws.com/0/39902/a5a28dd7-d736-42ec-b133-e1348c1e066f.png">

###チェックポイント実行プロパティの確認

登録したチェックポイントにはそれぞれプロパティを設定することができ、設定によってデバッグの内容が変わります。
ここではプロパティの設定画面を確認します。

1. [Checkpoint Locations]リストでチェックポイントを選択し、 *Edit Properties* ボタンをクリックします。
2. プロパティの設定画面が表示されます。デフォルトでは以下のような設定になっています。  
<img src="https://qiita-image-store.s3.amazonaws.com/0/39902/e313752f-b84b-7235-c1d6-5f9097feec77.png" width="320">

### チェックポイントの実行
デバッグの内容に応じてプロパティの設定を変更します。

#### メモリ内のオブジェクト・変数の状態を参照する
チェックポイント到達時点でのオブジェクト・変数の状態を参照します。

1. チェックポイントのプロパティ設定画面を開き、以下のとおり設定します。
  - **Dump Heap**: チェックする
  - **Apex Script Type**: *None* を選択
2. メニューから [Debug] > [Open Execute Anonymous Window] を開き、以下のコードを入力して実行します。  
```
CheckPointSample.createAccounts();
```
3. デバッグが行われ、[Checkpoints]タブ > [Checkpoints]リストに結果が表示されます。ダブルクリックすると詳細が表示されます。  
<img src="https://qiita-image-store.s3.amazonaws.com/0/39902/79abf606-f5f8-24b5-adb1-2a264e2aa563.png" width="400">
4. [Symbols]タブを開くと、オブジェクトや変数の一覧がツリー構造で表示されます。展開すると詳細が表示されます。　　
<img width="６００" alt="スクリーンショット 2016-12-10 13.09.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/39902/20e4d715-037b-01e6-51e1-efa5f81d0efc.png">
5. [Heap]タブを開くと、メモリ内にあるすべてのオブジェクト情報が表示され、[Types]リストに項目がデータ型別に分類されています。項目をクリックすると、より詳細な情報が表示されます。
<img width="800" alt="スクリーンショット 2016-12-10 13.09.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/39902/aeaed0ef-118f-b603-df26-3774d2453299.png">

#### データベースの状態を参照する
チェックポイント到達時点でSOQLを実行し、データベースのレコードを参照します。

1. チェックポイントのプロパティ設定画面を開き、以下のとおり設定します。
  - **Dump Heap**: （ON/OFFどちらでも可）
  - **Action Script Type**: *SOQL* を選択
  - **Action Script**: 以下のSOQL文を入力  
```
SELECT Id, Name, AccountNumber, CreatedDate FROM Account ORDER BY CreatedDate
```
2. メニューから [Debug] > [Open Execute Anonymous Window] を開き、以下のコードを入力して実行します。  ```CheckPointSample.createAccounts();```
3. デバッグが行われ、[Checkpoints]タブ > [Checkpoints]リストに結果が表示されます。ダブルクリックすると詳細が表示されます。  
4. [Query Results]タブを開くとSOQLの実行結果が表示されます。
<img width="600" src="https://qiita-image-store.s3.amazonaws.com/0/39902/23b6b1a9-c5c0-c20d-ff45-29965f2f89f0.png">
CheckPointSample.createAccounts() で作成した取引先レコードが表示されていることが確認できます。

#### Apexコードを実行する
チェックポイント到達時点でApexコードを実行し、実行結果を参照します。

1. チェックポイントのプロパティ設定画面を開き、以下のとおり設定します。
  - **Dump Heap**: （ON/OFFどちらでも可）
  - **Action Script Type**: *Apex Code* を選択
  - **Action Script**: 以下のApexコードを入力[^1]
```
System.assertNotEquals(0, [SELECT COUNT() FROM Account]);
```
2. メニューから [Debug] > [Open Execute Anonymous Window] を開き、以下のコードを入力して実行します。   
```
CheckPointSample.createAccounts();
```
3. デバッグが行われ、[Checkpoints]タブ > [Checkpoints]リストに結果が表示されます。ダブルクリックすると詳細が表示されます。  
4. [Apex Execution Results]タブが表示され、Apexコードの成否を確認することができます。  
<img width="340" src="https://qiita-image-store.s3.amazonaws.com/0/39902/94302790-0c3f-a7b3-3eba-2b5ec9a98e76.png">

  - Apexコードがエラーになった場合は、結果が以下のように表示されます。  
<img width="360" src="https://qiita-image-store.s3.amazonaws.com/0/39902/c4b358bc-227b-de1a-fe8d-15350b0bf01e.png">

なお、ここで ```System.debug()``` を実行しても出力結果を確認することはできませんでした。

[^1]: Action ScriptからApexクラス内のオブジェクトや変数を参照することはできません。Staticな要素のみ参照可能です。

### チェックポイントの削除
登録したチェックポイントをすべて削除するには、開発者コンソールで以下のメニューを実行します。
[Debug] > [Clear] > [Checkpoint Locations]

### 注意事項

- 開発者コンソールを閉じているとチェックポイントは実行されません。Apexコードが実行される前に開発者コンソールを開いたままにしておく必要があります。
- チェックポイントは最大5個まで登録可能です。
- forループ内の行にチェックポイントを登録した場合は、デバッグは1回だけ実行されます。[Checkpoint Locations]リストで *Iteration* の値を変更すると、何回目のループ時にチェックポイントを実行するかを設定できます。
<img width="400" src="https://qiita-image-store.s3.amazonaws.com/0/39902/0a65a8fa-4057-0c83-8993-ae095cebb1ef.png">


## 参考リンク

- [Apex コードへのチェックポイントの設定 | Salesforce](https://help.salesforce.com/apex/HTViewHelpDoc?id=code_dev_console_checkpoints_setting.htm&language=ja)
- [Checkpoints (チェックポイント) タブ | Salesforce](https://help.salesforce.com/apex/HTViewHelpDoc?id=code_dev_console_tab_checkpoints.htm&language=ja)
- [チェックポイントインスペクタ | Salesforce](https://help.salesforce.com/apex/HTViewHelpDoc?id=code_dev_console_view_checkpoints.htm&language=ja)
- [Apex コードと SOQL ステートメントのオーバーレイ表示 | Salesforce](https://help.salesforce.com/apex/HTViewHelpDoc?id=code_dev_console_checkpoints_overlaying_soql.htm&language=ja)