14
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Salesforce】Apexテストクラスの書き方(ベストプラクティス)

Posted at

#テスト用のデータはTestDataFactoryクラスで作る
TestDataFactoryにテストレコード作成処理を纏めます。
こうすることで、各々のテストクラスで行うテストレコード作成を共通化します。

【サンプルコード】

public with sharing class TestDataFactory {

    public static User createTestUser(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.LastName = name;
        user.Alias = user.UserName.split('@')[0].left(8);
        user.ProfileId = profileId;
        user.EmailEncodingKey = 'ISO-2022-JP';
        user.LanguageLocaleKey = 'ja';
        user.LocaleSidKey = 'ja_JP';
        user.TimeZoneSidKey = 'Asia/Tokyo';
        insert user;
        return user;
    }

    public static Profile getStandardProfile(){
        List<Profile> profiles = new List<Profile>();
        profiles =  [
            SELECT Id 
            FROM Profile
            WHERE Name IN ('標準ユーザ','Standard User' )
            LIMIT 1];
        return profiles[0];
    }

    public static void assignPermissionSet (Id userId, String permissionSetName){
        PermissionSet permissionSet = [SELECT Id FROM PermissionSet WHERE Name = :permissionSetName];
        PermissionSetAssignment permissionSetAssignment = new PermissionSetAssignment(PermissionSetId = permissionSet.Id, AssigneeId = userId);
        Insert permissionSetAssignment;
    }

    public static List<Contact> createContactWithAccount( Integer numContacts ){
        List<Account> accounts = new List<Account>();

        for( Integer i=0; i<numContacts; i++ ){
            Account account = new Account(Name='TestAccount' + i);
            accounts.add(account);
        }
        insert accounts;

        List<Contact> contacts = new List<Contact>();

        for( Integer i=0; i<numContacts; i++ ){
            Contact contact = new Contact(LastName='TestContact' + i, Account=accounts[i]);
            contacts.add(contact);
        }
        insert contacts;

        return contacts;

    }

    public static List<Contact> createContactWithoutAccount( Integer numContacts ){

        List<Contact> contacts = new List<Contact>();

        for( Integer i=0; i<numContacts; i++ ){
            Contact contact = new Contact(LastName='TestContact' + i);
            contacts.add(contact);
        }
        insert contacts;

        return contacts;

    }


    public static List<Contact> createDddContactWithAccount( Integer numContacts ){
        List<Account> accounts = new List<Account>();

        for( Integer i=0; i<numContacts; i++ ){
            Account account = new Account(Name='TestAccount' + i);
            accounts.add(account);
        }
        insert accounts;

        List<Contact> contacts = new List<Contact>();

        for( Integer i=0; i<numContacts; i++ ){
            Contact contact = new Contact(LastName='TestContact' + i, Account=accounts[i], LeadSource = 'DDD');
            contacts.add(contact);
        }
        insert contacts;

        return contacts;

    }

    public static List<Contact> createDddContactWithoutAccount( Integer numContacts ){

        List<Contact> contacts = new List<Contact>();

        for( Integer i=0; i<numContacts; i++ ){
            Contact contact = new Contact(LastName='TestContact' + i, LeadSource = 'DDD');
            contacts.add(contact);
        }
        insert contacts;

        return contacts;

    }

}



#テストメソッド名にルールを
テストメソッドは以下の規則で名前を付けましょう。
名前だけでどのようなテストを行うかを明示的に示します。

【命名規則】
テスト対象のメソッド名_シナリオ_期待される振る舞い

【サンプルコード】


    @isTest
    static void createNewContact_CorrectParams_ReturnId(){

        Account parentAccount = new Account();
        parentAccount.Name = 'TestAccount';
        parentAccount.Phone = '11111111111';

        Contact newContact = new Contact();
        newContact.LastName = 'Test';
        newContact.FirstName = 'Contact';

        ContactApplicationService contactApplicationService = new ContactApplicationService();

        Id newContactId;

        Test.startTest();
        System.runAs(getTestUser()){
            newContactId= contactApplicationService.createNewContact(parentAccount,newContact);
        }
        Test.stopTest();

        Contact resultContact = [ 
            SELECT Id
            FROM Contact 
            WHERE Account.Name =: parentAccount.Name AND Account.Phone =: parentAccount.Phone AND LastName =: newContact.LastName AND FirstName =: newContact.FirstName
            ];

        System.assertEquals( newContactId, resultContact.Id );

    }

#マジックStringを避ける
マジックStringとはこういった値です。
これだとTestという値がどのような影響を及ぼすかは分かりません。

Id newAccountId = AccountService.create( 'Test' );

ではこれだとどうでしょう?

static final String ACCOUNT_NAME = 'Test';
Id newAccountId = AccountService.create( ACCOUNT_NAME );

Testという値が、取引先オブジェクトの名前であることが直ぐに分かります。
コーディングした人以外にも値の意味が分かるように、定数に値の用途を吹き込みます。

#テスト対象の処理をTest.startTest()とTest.stopTest()で囲む
テストメソッド内の準備で、DML処理やSOQLを発行する事はあるかと思います。
その際、ガバナ制限である、1トランザクションあたりのDML処理上限数やSOQL発行上限数を消化してしまいます。
準備時の消費はテストに換算すべきでないので、Test.startTest()によりリセットします。
Test.stopTest()をつける事も忘れずに。

【サンプルコード】


        Test.startTest();
        Id newContactId = contactApplicationService.createNewContact(parentAccount,newContact);
        Test.stopTest();

#System.runAsでテスト対象のユーザを指定する
System.runAs無しで実行すると、システム実行となり権限を考慮したテストが出来なくなります。
なので、必ずSystem.runAsにてテスト対象のユーザを指定して実行します。

【サンプルコード】

        Test.startTest();
        System.runAs(getTestUser()){
            Id newContactId = contactApplicationService.createNewContact(parentAccount,newContact);
        }
        Test.stopTest();

#assertEqualsは1テストに1つ

assertEqualsを複数入れてしまうと、何をテストしたいかが不明確になります。
あと、最初のassertEqualsで失敗すると次のassertEqualsが評価されないためテストもし難くなります。

14
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?