Apex テストクラス

####クラスの定義
SeeAllData=trueにすると既存のデータが参照できるようになるが、通常はfalseとする（ConnectAPIとか一部の機能はtrueじゃないと実行できないので注意）

```java:
@isTest(SeeAllData=false)
private class Ron_xxxControllerTest {

    @isTest 
    static void runProperties() {

    //testMethod の仕様は非推奨になっているため使わない。@isTestを使う
    public static testMethod void testXXX(){

```
####テストメソッドの雛形
```java:
/*
 * target function:
 */ 
@isTest 
static void testXX() {
    //prepare user
    User u1 = TestUtil.createUser('test1');
        
    //execute and assert
    System.runAs(u1){
        //prepare test data

        //execute test
        Test.startTest();
            
        System.assertEquals(expected, actual);
        Test.stopTest();
    }
}
```
####assert
`System.assertEquals(期待値, 実際の値);`
`System.assert(評価の式);`

####テスト用にGETパラメータをセットする
`ApexPages.currentPage().getParameters().put('xxxItemId', '');`
####start/end
startとstopをセットで使用すること。startとstopの間だけでガバナ制限がカウントされ、データ準備のためのコード実行分がカウントされない。

```java:
Test.startTest();
・・・
Test.stopTest();
```
####runAs
特定のユーザーコンテキスト下でテストを実施する。

```java:
User u1 = createTestUser();
System.runAs(u1){
 ・・・
}
```
####カスタム設定
SeeAllData=false環境下ではカスタム設定にもデータが設定されないことに注意。テストメソッド内でデータを準備する必要がある

```java:
public static xxx_Properties__c prepareCustomSettings(){
    xxx_Properties__c settings = new xxx_Properties__c();
    settings.Name = 'XXX';
    settings.email = 'aaa@aaa.com';
    insert settings;
        
    return settings;
}
```

####VF拡張コントローラのテスト StandardController
```java 
//StandardControllerをnewして、コントローラに渡す
XX__c instance = new XX__c();
instance.xx__c = '123';
Apexpages.Standardcontroller sc = new Apexpages.Standardcontroller(instance);

XX_VF_Ctrl contl = new XX_VF_Ctrl(sc);

```

####トリガーのValidationチェックのテスト(addError()を使うケース
```java
try{
    insert c1;  //error
    System.assert(false); //例外が発生すべき
}catch(DmlException e)
}
```

####テスト時に自動採番が増えないようにするオプション
[開発]-[Apexテスト実行]-[オプション]
「独立した自動採番順序」をチェックする
<img width="544" alt="Screen Shot 2017-02-10 at 14.20.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/161463/75cf07da-d69a-7185-6d22-15d1c4764d4e.png">


#### テストユーザーの作成コード
```java
/*
 * create a test user
 *  name: firstName
 */
public static User createUser(String name){
    Profile profile = getStandardProfile();
    String profileId = profile.id;

    User user = new User();
    user.Email = name + 'test@xx.xxx.com';
    user.UserName = name + 'test@xx.xxx.com';
    user.FirstName = name;
    user.LastName = '123';
    user.Alias = user.UserName.split('@')[0].left(8);
    user.ProfileId = profileId;
    //user.UserRoleId = role.Id;
    user.EmailEncodingKey = 'ISO-2022-JP';
    user.LanguageLocaleKey = 'ja';
    user.LocaleSidKey = 'ja_JP';
    user.TimeZoneSidKey = 'Asia/Tokyo';
    insert user;
    user = [select Name, UserName, FirstName, LastName, Alias, UserRoleId, ProfileId, CreatedDate from user where UserName = :user.Username limit 1];
        
    return user;
 }

/*
 * get Profile of standard user
 */ 
public static Profile getStandardProfile(){
    Profile[] profiles;
    profiles =  [select Id From Profile where Name = '標準ユーザ' limit 1];
    if (profiles.isEmpty()){
       profiles =  [select Id From Profile where Name = 'Standard User' limit 1];
    }
    return profiles[0];
}
```

####テスト実行時にprivateテストにアクセスできるようにする
`@TestVisible` を付ける

####テスト実行時に特定のコードブロックを実行させないようにする
```java
if (!Test.isRunningTest()) { 
    ....
}
```

####MIXED_DML_EXCEPTIONの回避方法
UserやUserRoleに対するDMLとそれ以外のオブジェクトへのDMLを同じトランザクションで実行していることが理由。
[説明](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_dml_non_mix_sobjects.htm)

テストクラスでの回避方法はSystem.runAsを使用する

```java
//use System.runAs block in order to avoid MIXED_DML_EXCEPTION
User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId()];
System.runAs (thisUser){
    ....
}

```

#### Standard PriceBook IDの取得方法
テストクラスの中でPricebookEntry()を作成したい場合は、下記の間数で標準価格表のIDを取得する

```java
Id pricebookId = Test.getStandardPricebookId();
PricebookEntry pbe = new PricebookEntry();
pbe.Product2Id = someProduct.Id;
pbe.Pricebook2Id = pricebookId;
pbe.UnitPrice = 0;
pbe.IsActive = true;
insert pbe;

```