ApexのテストにおけるアサーションとSystem.runAs()の活用

# **Salesforce Apex のテストにおけるアサーションと System.runAs() の活用**  
Apex のテストでは、**アサーション (Assertion) を使用して実行結果を検証** します。また、**System.runAs() を使ったセキュリティテスト** や、**混合 DML エラーの回避** についても解説します。  

---

# **1. アサーションを使用した実行結果の検証**
### **アサーションとは？**
アサーションは、**テストの期待値と実際の結果を比較して、正しく動作しているかを確認する** ためのものです。Apex では `System` クラスのメソッドを使ってアサーションを行います。

---

## **1.1 System クラスのアサーション一覧**
| メソッド | 説明 |
|----------|----------------------------------------------|
| `System.assert(condition)` | `condition` が `true` であることを検証 |
| `System.assert(condition, message)` | `condition` が `true` でない場合、`message` を表示 |
| `System.assertEquals(expected, actual)` | `expected` と `actual` が等しいことを検証 |
| `System.assertEquals(expected, actual, message)` | `expected` と `actual` が等しくない場合、`message` を表示 |
| `System.assertNotEquals(unexpected, actual)` | `unexpected` と `actual` が異なることを検証 |
| `System.assertNotEquals(unexpected, actual, message)` | `unexpected` と `actual` が等しい場合、`message` を表示 |

---

## **1.2 アサーションの実際の使用例**
### **✅ `System.assert()` の例**
```apex
@isTest
private class AssertExampleTest {
    @isTest
    static void testAssert() {
        Boolean isActive = true;
        System.assert(isActive, 'isActive should be true');
    }
}
```
> **ポイント:**  
> `isActive` が `true` であることを検証します。`false` の場合、テストは失敗し、エラーメッセージが表示されます。

---

### **✅ `System.assertEquals()` の例**
```apex
@isTest
private class AssertExampleTest {
    @isTest
    static void testAssertEquals() {
        Integer expected = 100;
        Integer actual = 50 + 50;
        System.assertEquals(expected, actual, 'Sum calculation is incorrect');
    }
}
```
> **ポイント:**  
> `actual` の値 (`50 + 50`) が `expected` (`100`) と一致するかを検証します。一致しない場合、エラーメッセージが表示されます。

---

### **✅ `System.assertNotEquals()` の例**
```apex
@isTest
private class AssertExampleTest {
    @isTest
    static void testAssertNotEquals() {
        String unexpected = 'Hello';
        String actual = 'World';
        System.assertNotEquals(unexpected, actual, 'Strings should not match');
    }
}
```
> **ポイント:**  
> `actual` (`'World'`) が `unexpected` (`'Hello'`) と異なることを確認します。  
> 一致していた場合、テストは失敗します。

---

# **2. `System.runAs()` を用いたセキュリティテスト**
## **2.1 `System.runAs()` とは？**
`System.runAs()` を使うと、**別のユーザーの権限で Apex コードを実行** できます。  
これにより、特定の **プロファイルや権限セットのユーザーが操作できるか** をテストできます。

---

## **2.2 `System.runAs()` の基本的な使い方**
```apex
@isTest
private class RunAsExampleTest {
    @isTest
    static void testRunAs() {
        // テストユーザーの作成
        User testUser = new User(
            LastName = 'Test User',
            Email = 'testuser@example.com',
            Username = 'testuser@example.com' + System.currentTimeMillis(),
            Alias = 'tuser',
            ProfileId = [SELECT Id FROM Profile WHERE Name = 'Standard User' LIMIT 1].Id,
            TimeZoneSidKey = 'America/Los_Angeles',
            LocaleSidKey = 'en_US',
            EmailEncodingKey = 'UTF-8',
            LanguageLocaleKey = 'en_US'
        );
        insert testUser;

        // testUser の権限で処理を実行
        System.runAs(testUser) {
            System.assertEquals(UserInfo.getUserId(), testUser.Id, 'User should be testUser');
        }
    }
}
```
> **ポイント:**  
> - `System.runAs(testUser)` の中では `testUser` の権限で処理が実行される  
> - `UserInfo.getUserId()` を使って現在のユーザーが `testUser` であることを確認  

---

## **2.3 `System.runAs()` による混合 DML エラーの回避**
### **混合 DML エラーとは？**
Apex では **標準オブジェクト（User など）とカスタムオブジェクトを同じトランザクションで操作するとエラー** になります。

```apex
@isTest
private class MixedDMLErrorExample {
    @isTest
    static void testMixedDML() {
        // ユーザーを作成（標準オブジェクト）
        User testUser = new User(
            LastName = 'Test User',
            Email = 'testuser@example.com',
            Username = 'testuser@example.com' + System.currentTimeMillis(),
            Alias = 'tuser',
            ProfileId = [SELECT Id FROM Profile WHERE Name = 'Standard User' LIMIT 1].Id,
            TimeZoneSidKey = 'America/Los_Angeles',
            LocaleSidKey = 'en_US',
            EmailEncodingKey = 'UTF-8',
            LanguageLocaleKey = 'en_US'
        );

        // カスタムオブジェクトのレコードを作成
        Pokemon__c p = new Pokemon__c(Name='Pikachu', Type__c='Electric');

        try {
            insert testUser;
            insert p; // ここでエラー（Mixed DML error）
        } catch (Exception e) {
            System.debug('混合 DML エラー: ' + e.getMessage());
        }
    }
}
```
> **このコードはエラーになります**（標準オブジェクト `User` と `Pokemon__c` を同じトランザクションで処理）

---

### **解決策: `System.runAs()` を使う**
```apex
@isTest
private class MixedDMLFixExample {
    @isTest
    static void testMixedDMLFixed() {
        // ユーザーを作成
        User testUser = new User(
            LastName = 'Test User',
            Email = 'testuser@example.com',
            Username = 'testuser@example.com' + System.currentTimeMillis(),
            Alias = 'tuser',
            ProfileId = [SELECT Id FROM Profile WHERE Name = 'Standard User' LIMIT 1].Id,
            TimeZoneSidKey = 'America/Los_Angeles',
            LocaleSidKey = 'en_US',
            EmailEncodingKey = 'UTF-8',
            LanguageLocaleKey = 'en_US'
        );
        insert testUser;

        // System.runAs() で混合 DML を回避
        System.runAs(testUser) {
            Pokemon__c p = new Pokemon__c(Name='Pikachu', Type__c='Electric');
            insert p; // User の作成とは別トランザクションになるためエラー回避
        }
    }
}
```
> **ポイント:**  
> - `System.runAs()` を使うと **標準オブジェクトとカスタムオブジェクトの DML を別トランザクションで処理** できる  
> - これにより **混合 DML エラーを回避** できる  

---

# **まとめ**
✅ **`System.assert()` を使ってテストの期待値を検証**  
✅ **`System.runAs()` を使って権限別の動作をテスト**  
✅ **`System.runAs()` を活用して `混合 DML エラー` を回避**  

これらの方法を活用すれば、**テストの品質を向上させ、エラーを未然に防ぐことが可能** です！🚀