Trigger_添付ファイルトリガー

#1.要求分析
　　業務レコードにメールを添付する際に、項目「メール有無」に「有」を表示する。
　　然もなければ、項目「メール有無」に「無」を表示する。

#2.基本設計
#####　1.新規トリガー：
　　対象業務レコードにファイルをアップロードする場合、
　　　　アップロード後残りファイルの中でメールファイルが存在する場合、
　　　　　　業務レコード.「メール有無」！＝「有」の場合、
　　　　　　　　「メール有無」＝「有」;
　　　　アップロード後残りファイルの中でメールファイルが存在しない場合、
　　　　　　業務レコード.「メール有無」！＝「無」の場合、
　　　　　　　　「メール有無」＝「無」
#####　2.更新トリガー：
　　対象業務レコードにファイルをバージョンアップする場合、
　　　　バージョンアップ後残りファイルの中でメールファイルが存在する場合、
　　　　　　業務レコード.「メール有無」！＝「有」の場合、
　　　　　　　　「メール有無」＝「有」;
　　　　バージョンアップ後残りファイルの中でメールファイルが存在しない場合、
　　　　　　業務レコード.「メール有無」！＝「無」の場合、
　　　　　　　　「メール有無」＝「無」
#####　3.削除トリガー：
　　**①レコードから削除：**
　　　対象業務レコードにファイルをレコードから削除する場合、
　　　　　レコードから削除後残りファイルの中でメールファイルが存在する場合、
　　　　　　　業務レコード.「メール有無」！＝「有」の場合、
　　　　　　　　　「メール有無」＝「有」;
　　　　　レコードから削除後残りファイルの中でメールファイルが存在しない場合、
　　　　　　　業務レコード.「メール有無」！＝「無」の場合、
　　　　　　　　　「メール有無」＝「無」

　　**②完全に削除：**
　　　対象業務レコードにファイルを完全に削除する場合、
　　　　　完全に削除後残りファイルの中でメールファイルが存在する場合、
　　　　　　　業務レコード.「メール有無」！＝「有」の場合、
　　　　　　　　　「メール有無」＝「有」;
　　　　　完全に削除後残りファイルの中でメールファイルが存在しない場合、
　　　　　　　業務レコード.「メール有無」！＝「無」の場合、
　　　　　　　　　「メール有無」＝「無」
#3.相関図
![スクリーンショット 2021-11-03 15.02.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487243/1df78348-d0b1-1031-65a7-99050c58517b.png)

*項目説明：*
#
| オブジェクト            | 項目Id             | 値/意味              |
|:--------------------|:-------------------|:--------------------|
| ContentDocumentLink | LinkedEntityId     | 業務レコード.Id        |
|                     | ContentDocumentId  | ContentDocument.Id  |
| ContentDocument     | Title              | 添付ファイルの表示名前   |
|                     | ContentSize        | 添付ファイルのサイズ     |
|                     | FileExtension      | 添付ファイルの拡張子     |
| ContentVersion      | ContentSize        | 添付ファイルのサイズ     |
|                     | FileExtension      | 添付ファイルの拡張子     |
|                     | ContentDocumentId  | ContentDocument.Id   |
|                     | Title              | 添付ファイルの表示名前    |
|                     | VersionNumber      | 添付ファイルのバージョン番号|






#4.流れ
######　1.アップロードの流れ
　　❶ファイルがContentVersionに挿入される
　　❷ContentDocumentに一つレコードが自動的に生成される
　　❸ContentDocumentLink.LinkedEntityId＝該当業務レコード.Id、
　　　ContentDocumentLink.ContentDocumentId＝ContentDocument.Id、
　　　ContentDocumentLinkに一つ業務関連レコードが挿入される;
　　　同時にもう一つユーザ関連レコードも生成される
######　2.バージョンアップの流れ
　　❶ContentVersionにVersionNumber採番で一つレコードが挿入される
######　3.レコードから削除の流れ
　　❶ContentDocumentLinkに一つ業務関連レコードが削除される
######　4.完全に削除の流れ
　　❶ContentVersionとContentDocumentのレコードが削除される
　　❷ContentDocumentLinkの業務とユーザ関連の二つレコードが削除される
#5.実装
######　1.新規トリガー
```java:ContentDocumentLink
trigger TR_ContentDocumentLink on ContentDocumentLink (after insert,after delete) {
    //====================
    // トリガ実行クラス
    //====================
    CL_ContentDocumentLinkTrg trgCon = new CL_ContentDocumentLinkTrg();

    if (Trigger.isAfter) {
        // 業務レコードに添付ファイルをアップロードする場合
        if (Trigger.isInsert) {
            trgCon.onAfterInsert(Trigger.new);
        }
        // 業務レコードの添付ファイルをレコードから削除する場合
        else if (Trigger.isDelete) {
            trgCon.onAfterDelete(Trigger.old);
        }
    }
}
```
```java:CL_ContentDocumentLinkTrg
public without sharing class CL_ContentDocumentLinkTrg {
    public static final String KBN_INSERT = '1';
    public static final String KBN_DELETE = '2';
    public static List<String> mailExtensionList = new List<String>();
 
    static {
        mailExtensionList = System.Label.CDL011_DFN_0002.split(',');
    }

    /**
    * After Insert 処理
    * @param newList Trigger.new
    * @return なし
    **/
    public void onAfterInsert(List<ContentDocumentLink> newList){
        // ★該当トリガーは1件のみ処理できる★
        // 対象業務オブジェクトのContentDocumentLinkList取得
        List<ContentDocumentLink> sObjectContentDocumentLinkList = getSObjectContentDocumentLinkList(newList);
        if (sObjectContentDocumentLinkList.isEmpty()) {
            return;
        }

        // 該当業務オブジェクト更新処理
        updateTravelRequest(sObjectContentDocumentLinkList, KBN_INSERT);
    }

    /**
    * After Delete 処理
    * @param oldList Trigger.old
    * @return なし
    **/
    public void onAfterDelete(List<ContentDocumentLink> oldList){
        // ★該当トリガーは1件のみ処理できる★
        // 対象業務オブジェクトのContentDocumentLinkList取得
        List<ContentDocumentLink> sObjectContentDocumentLinkList = getSObjectContentDocumentLinkList(oldList);
        if (sObjectContentDocumentLinkList.isEmpty()) {
            return;
        }

        // 該当業務オブジェクト更新処理
        updateTravelRequest(sObjectContentDocumentLinkList, KBN_DELETE);
    }

    /**
    * 添付ファイルを新規、レコードから削除する場合、対象業務オブジェクトのContentDocumentLinkList取得
    * @param newOldList 添付ファイルを新規する場合、Trigger.new；添付ファイルをレコードから削除する場合、Trigger.old
    * @return ContentDocumentLinkのリスト
    **/
    private List<ContentDocumentLink> getSObjectContentDocumentLinkList(List<ContentDocumentLink> newOldList) {
        List<ContentDocumentLink> contentDocumentLinkList = new List<ContentDocumentLink>();
        for (SObject item : newOldList) {
            ContentDocumentLink cdLink = (ContentDocumentLink)item;
            if (cdLink.LinkedEntityId.getSObjectType() == Travel_Request__c.getSObjectType()) {
                contentDocumentLinkList.add(cdLink);
            }
        }

        return contentDocumentLinkList;
    }

    /**
    * 添付ファイルを新規、レコードから削除する場合、該当業務オブジェクト更新処理
    * @param contentDocumentLinkList 添付ファイルを新規する場合、ファイルタイプはメールタイプのContentDocumentLinkList；添付ファイルをレコードから削除する場合、対象業務オブジェクトのContentDocumentLinkList
    * @param shoriKbn 処理区分＝'1'、添付ファイルを新規用の業務オブジェクト更新処理；処理区分＝'2'、添付ファイルをレコードから削除用の業務オブジェクト更新処理
    * @return なし
    **/
    private void updateTravelRequest(List<ContentDocumentLink> contentDocumentLinkList,String shoriKbn) {
        // 件数
        Integer cnt;
        // 業務レコードIdを取得する
        Id entityId = contentDocumentLinkList.get(0).LinkedEntityId;
        // ContentDocumentIdを取得する
        Id contentDocumentId = contentDocumentLinkList.get(0).ContentDocumentId;
        // 業務オブジェクト更新の多端末制御処理
        Travel_Request__c travelRequestcDataLock = [
            SELECT
                Id,
                SofuMailUmu__c
            FROM
                Travel_Request__c
            WHERE
                Id = :entityId
            FOR  UPDATE];

        // 添付ファイルを新規する場合
        if (shoriKbn == KBN_INSERT) {
            // アップロード後、メールタイプな添付ファイル有無確認
            cnt = [
                SELECT
                    count()
                FROM
                    ContentDocumentLink
                WHERE
                        LinkedEntityId  = :entityId 
                    AND ContentDocument.FileExtension IN :CL_ContentDocumentLinkTrg.mailExtensionList];
        }
        // 業務レコードから削除するの場合
        else if (shoriKbn == KBN_DELETE) {
            // 削除後、メールタイプな添付ファイル有無確認
            cnt = [
                SELECT
                    count()
                FROM
                    ContentDocumentLink
                WHERE
                        LinkedEntityId  = :entityId 
                    AND ContentDocumentId != :contentDocumentId
                    AND ContentDocument.FileExtension IN :CL_ContentDocumentLinkTrg.mailExtensionList];
        }

        // 業務レコードを更新する
        if (cnt == 0 && travelRequestcDataLock.SofuMailUmu__c != '無') {
            Travel_Request__c travelRequest = new Travel_Request__c();
            travelRequest.Id = entityId;
            travelRequest.SofuMailUmu__c = '無';

            update travelRequest;
        } else if(cnt != 0 && travelRequestcDataLock.SofuMailUmu__c != '有') {
            Travel_Request__c travelRequest = new Travel_Request__c();
            travelRequest.Id = entityId;
            travelRequest.SofuMailUmu__c = '有';

            update travelRequest;
        }
    }
}
```
######　2.更新トリガー
```java:TR_ContentVersion
trigger TR_ContentVersion on ContentVersion (after insert) {
    //====================
    // トリガ実行クラス
    //====================
    CL_ContentVersionTrg trgCon = new CL_ContentVersionTrg();

    if (Trigger.isAfter) {
    	if (Trigger.isInsert) {
    		trgCon.onAtertInsert(Trigger.new);
       	}
    }
}
```
```java:CL_ContentVersionTrg
public without sharing class CL_ContentVersionTrg {
    /**
    * After Insert 処理
    * @param newList Trigger.new
    * @return なし
    **/
    public void onAtertInsert(List<ContentVersion> newList){
        // ★該当トリガーは1件のみ処理できる★
        // ContentVersionの処理対象を取得する
        ContentVersion cVersion = (ContentVersion)Trigger.new.get(0);

        // 古いファイルバージョン有無判断
        if(Integer.valueOf(cVersion.VersionNumber) > 1 ){
            // ContentDocumentLinkデータを取得する
            List<ContentDocumentLink> contentDocumentLinkAllList = [
            SELECT
                Id,
                LinkedEntityId,
                ContentDocumentId
            FROM
                ContentDocumentLink
            WHERE
                ContentDocumentId  = :cVersion.ContentDocumentId];

            // 業務オブジェクト対象データ取得
            List<ContentDocumentLink> contentDocumentLinkList = new List<ContentDocumentLink>();
            for (SObject item : contentDocumentLinkAllList) {
                ContentDocumentLink cdLink = (ContentDocumentLink)item;
                    if (cdLink.LinkedEntityId.getSObjectType() == Travel_Request__c.getSObjectType()) {
                        contentDocumentLinkList.add(cdLink);
                }
            }
            if (contentDocumentLinkList.isEmpty()) {
                return;
            }

            // 業務レコードIdを取得する
            Id entityId = contentDocumentLinkList.get(0).LinkedEntityId;

            // 業務オブジェクト更新の多端末制御処理
            Travel_Request__c travelRequestDataLock = [
                SELECT
                    Id,
                    SofuMailUmu__c
                FROM
                    Travel_Request__c
                WHERE
                    Id = :entityId
                FOR  UPDATE];

            // 更新後、メール方式添付ファイル有無確認
            Integer cnt = [
                SELECT
                    count()
                FROM
                    ContentDocumentLink
                WHERE
                        LinkedEntityId  = :entityId
                    AND ContentDocument.FileExtension IN :CL_ContentDocumentLinkTrg.mailExtensionList];

            // 業務レコードを更新する
            if (cnt == 0 && travelRequestDataLock.SofuMailUmu__c != '無') {
                Travel_Request__c travelRequest = new Travel_Request__c();
                travelRequest.Id = entityId;
                travelRequest.SofuMailUmu__c = '無';
    
                update travelRequest;
            } else if(cnt != 0 && travelRequestDataLock.SofuMailUmu__c != '有') {
                Travel_Request__c travelRequest = new Travel_Request__c();
                travelRequest.Id = entityId;
                travelRequest.SofuMailUmu__c = '有';
    
                update travelRequest;
            }
        }
    }
}
```
######　3.削除トリガー
```java:TR_ContentDocument
trigger TR_ContentDocument on ContentDocument (before delete) {
    //====================
    // トリガ実行クラス
    //====================
    CL_ContentDocumentTrg trgCon = new CL_ContentDocumentTrg();

    if (Trigger.isBefore) {
        if (Trigger.isDelete) {
            trgCon.onBeforDelete(Trigger.old);
        }
    }
}
```
```java:CL_ContentDocumentTrg
public without sharing class CL_ContentDocumentTrg {
    /**
    * Before Delete 処理
    * @param oldList Trigger.old
    * @return なし
    **/
    public void onBeforDelete(List<ContentDocument> oldList){
        // ★該当トリガーは1件のみ処理できる★
        //ContentDocumentの処理対象を取得する
        ContentDocument cDocument = (ContentDocument)Trigger.old.get(0);
        // ContentDocumentLinkデータを取得する
        List<ContentDocumentLink> contentDocumentLinkAllList = [
            SELECT
                Id,
                LinkedEntityId,
                ContentDocumentId
            FROM
                ContentDocumentLink
            WHERE
                ContentDocumentId  = :cDocument.Id];

        // 業務オブジェクト対象データ取得
        List<ContentDocumentLink> contentDocumentLinkList = new List<ContentDocumentLink>();
        for (SObject item : contentDocumentLinkAllList) {
            ContentDocumentLink cdLink = (ContentDocumentLink)item;
                if (cdLink.LinkedEntityId.getSObjectType() == Travel_Request__c.getSObjectType()) {
                    contentDocumentLinkList.add(cdLink);
            }
        }
        if (contentDocumentLinkList.isEmpty()) {
            return;
        }

        // 業務レコードIdを取得する
        Id entityId = contentDocumentLinkList.get(0).LinkedEntityId;

        // 業務オブジェクト更新の多端末制御処理
        Travel_Request__c travelRequestDataLock = [
            SELECT
                Id,
                SofuMailUmu__c
            FROM
                Travel_Request__c
            WHERE
                Id = :entityId
            FOR  UPDATE];

        // 削除後、メールタイプな添付ファイル有無確認
        Integer cnt = [
            SELECT
                count()
            FROM
                ContentDocumentLink
            WHERE
                    LinkedEntityId  = :entityId 
                AND ContentDocumentId != :cDocument.Id
                AND ContentDocument.FileExtension IN :CL_ContentDocumentLinkTrg.mailExtensionList];

        // 業務レコードを更新する
        if (cnt == 0 && travelRequestDataLock.SofuMailUmu__c != '無') {
            Travel_Request__c travelRequest = new Travel_Request__c();
            travelRequest.Id = entityId;
            travelRequest.SofuMailUmu__c = '無';

            update travelRequest;
        } else if(cnt != 0 && travelRequestDataLock.SofuMailUmu__c != '有') {
            Travel_Request__c travelRequest = new Travel_Request__c();
            travelRequest.Id = entityId;
            travelRequest.SofuMailUmu__c = '有';

            update travelRequest;
        }
    }    
}
```
#6.テストクラース
######　1.新規トリガーのテストクラース
```java:CL_Test_ContentDocumentLinkTrg
@isTest
private class CL_Test_ContentDocumentLinkTrg {
    //testSetupデータ準備
    @testSetup
    static void setup() {
        Travel_Request__c tmp = new Travel_Request__c();
        tmp.TravelRequestName__c = 'テスト01';
        insert tmp;

    }

    @isTest static void afterInsertTest01() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        Travel_Request__c record = [SELECT Id FROM Travel_Request__c Limit 1];

        // 添付ファイル作成
        contentversion cv = new contentversion();
        cv.contentlocation = 'S';
        cv.PathOnClient = 'sample.xlsx';
        cv.Title = 'sample';
        cv.VersionData = Blob.valueOf('sample file');
        insert cv;
        
        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        insert cdl;
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('無', result.SofuMailUmu__c);
    }

    @isTest static void afterInsertTest02() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        Travel_Request__c record = [SELECT Id FROM Travel_Request__c Limit 1];

        // 添付ファイル作成
        contentversion cv = new contentversion();
        cv.contentlocation = 'S';
        cv.PathOnClient = 'sample.'+CL_ContentDocumentLinkTrg.mailExtensionList.get(0);
        cv.Title = 'sample';
        cv.VersionData = Blob.valueOf('sample file');
        insert cv;
        
        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        insert cdl;
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('有', result.SofuMailUmu__c);
    }

    @isTest static void afterInsertTest03() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        Travel_Request__c record = [SELECT Id FROM Travel_Request__c Limit 1];

        // 添付ファイル作成
        contentversion cv = new contentversion();
        cv.contentlocation = 'S';
        cv.PathOnClient = 'sample';
        cv.Title = 'sample';
        cv.VersionData = Blob.valueOf('sample file');
        insert cv;
        
        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        insert cdl;
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('無', result.SofuMailUmu__c);
    }
}
```
######　2.更新トリガーのテストクラース
```java:CL_Test_ContentVersionTrg
@isTest
private class CL_Test_ContentVersionTrg {
    //testSetupデータ準備
    @testSetup
    static void setup() {
        Travel_Request__c tmp = new Travel_Request__c();
        tmp.TravelRequestName__c = 'テスト01';
        insert tmp;

    }

    @isTest static void afterInsertTest01() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        Travel_Request__c record = [SELECT Id FROM Travel_Request__c Limit 1];

        // 添付ファイル作成
        contentversion cv1 = new contentversion();
        cv1.contentlocation = 'S';
        cv1.PathOnClient = 'sample.xlsx';
        cv1.Title = 'sample';
        cv1.VersionData = Blob.valueOf('sample fileOld');
        insert cv1;
        
        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;
        insert cdl;

        // 添付ファイル更新
        contentversion cv2 = new contentversion();
        cv2.contentlocation = 'S';
        cv2.PathOnClient = 'sample.msg';
        cv2.Title = 'sample';
        cv2.VersionData = Blob.valueOf('sample fileNew');
        cv2.ContentDocumentId = cvDocument.ContentDocumentId;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        insert cv2;
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('有', result.SofuMailUmu__c);
    }

    @isTest static void afterInsertTest02() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        Travel_Request__c record = [SELECT Id FROM Travel_Request__c Limit 1];

        // 添付ファイル作成
        contentversion cv1 = new contentversion();
        cv1.contentlocation = 'S';
        cv1.PathOnClient = 'sample.msg';
        cv1.Title = 'sample';
        cv1.VersionData = Blob.valueOf('sample fileOld');
        insert cv1;
        
        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;
        insert cdl;

        // 添付ファイル更新
        contentversion cv2 = new contentversion();
        cv2.contentlocation = 'S';
        cv2.PathOnClient = 'sample.xlsx';
        cv2.Title = 'sample';
        cv2.VersionData = Blob.valueOf('sample fileNew');
        cv2.ContentDocumentId = cvDocument.ContentDocumentId;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        insert cv2;
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('無', result.SofuMailUmu__c);
    }

    @isTest static void afterInsertTest03() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        user record = [SELECT Id FROM user Limit 1];

        // 添付ファイル作成
        contentversion cv1 = new contentversion();
        cv1.contentlocation = 'S';
        cv1.PathOnClient = 'sampleOld';
        cv1.Title = 'sampleOld';
        cv1.VersionData = Blob.valueOf('sample fileOld');
        insert cv1;
        
        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sampleOld' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;
        insert cdl;

        // 添付ファイル更新
        contentversion cv2 = new contentversion();
        cv2.contentlocation = 'S';
        cv2.PathOnClient = 'sampleNew';
        cv2.Title = 'sampleNew';
        cv2.VersionData = Blob.valueOf('sample fileNew');
        cv2.ContentDocumentId = cvDocument.ContentDocumentId;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        insert cv2;
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('無', result.SofuMailUmu__c);
    }
}
```
######　3.削除トリガーのテストクラース
```java:CL_Test_ContentDocumentTrg
@isTest
private class CL_Test_ContentDocumentTrg {
    //testSetupデータ準備
    @testSetup
    static void setup() {
        User u = new User();
        u.LastName = 'テスト';
        u.FirstName = '太郎';
        u.Email = 'test@test.com';
        u.UserName = 'GLS_test@test.com.sample';
        u.Alias = 'glstest';
        u.ProfileId = UserInfo.getProfileId();
        u.EmailEncodingKey = 'ISO-2022-JP';
        u.TimeZoneSidKey = 'Asia/Tokyo';
        u.LocaleSidKey = 'ja_JP';
        u.LanguageLocaleKey = 'ja';
        insert u;

        Travel_Request__c tmp = new Travel_Request__c();
        tmp.TravelRequestName__c = 'テスト01';
        insert tmp;

    }

    @isTest static void beforeDeleteTest01() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        Travel_Request__c record = [SELECT Id FROM Travel_Request__c Limit 1];

        // 添付ファイル作成
        contentversion cv = new contentversion();
        cv.contentlocation = 'S';
        cv.PathOnClient = 'sample.xlsx';
        cv.Title = 'sample';
        cv.VersionData = Blob.valueOf('sample file');
        insert cv;
        
        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;
        insert cdl;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        delete [SELECT Id FROM ContentDocument];
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('無', result.SofuMailUmu__c);
    }

    @isTest static void beforeDeleteTest02() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        Travel_Request__c record = [SELECT Id FROM Travel_Request__c Limit 1];

        // 添付ファイル作成
        contentversion cv = new contentversion();
        cv.contentlocation = 'S';
        cv.PathOnClient = 'sample.'+CL_ContentDocumentLinkTrg.mailExtensionList.get(0);
        cv.Title = 'sample';
        cv.VersionData = Blob.valueOf('sample file');
        insert cv;
        
        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;
        insert cdl;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        delete [SELECT Id FROM ContentDocument];
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('無', result.SofuMailUmu__c);
    }

    @isTest static void beforeDeleteTest03() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        Travel_Request__c record = [SELECT Id FROM Travel_Request__c Limit 1];

        // 添付ファイル作成
        contentversion cv = new contentversion();
        cv.contentlocation = 'S';
        cv.PathOnClient = 'sample';
        cv.Title = 'sample';
        cv.VersionData = Blob.valueOf('sample file');
        insert cv;
        
        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;
        insert cdl;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        delete [SELECT Id FROM ContentDocument];
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('無', result.SofuMailUmu__c);
    }

    @isTest static void beforeDeleteTest04() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // ユーザテストデータ取得
        user record = [SELECT Id FROM user Limit 1];

        // 添付ファイル1作成
        contentversion cv1 = new contentversion();
        cv1.contentlocation = 'S';
        cv1.PathOnClient = 'sample1';
        cv1.Title = 'sample1';
        cv1.VersionData = Blob.valueOf('sample file1');
        insert cv1;

        // 添付ファイル2作成
        contentversion cv2 = new contentversion();
        cv2.contentlocation = 'S';
        cv2.PathOnClient = 'sample2';
        cv2.Title = 'sample2';
        cv2.VersionData = Blob.valueOf('sample file2');
        insert cv2;
        
        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample1' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;
        insert cdl;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        delete [SELECT Id FROM ContentDocument];
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('無', result.SofuMailUmu__c);
    }

    @isTest static void afterDeleteTest01() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        Travel_Request__c record = [SELECT Id FROM Travel_Request__c];

        // 添付ファイル作成
        contentversion cv = new contentversion();
        cv.contentlocation = 'S';
        cv.PathOnClient = 'sample.'+CL_ContentDocumentLinkTrg.mailExtensionList.get(0);
        cv.Title = 'sample';
        cv.VersionData = Blob.valueOf('sample file');
        insert cv;

        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;
        insert cdl;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        delete cdl;
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('無', result.SofuMailUmu__c);
    }

    @isTest static void afterDeleteTest02() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // ユーザデータ取得
        user record = [SELECT Id FROM user Limit 1];

        // 添付ファイル作成
        contentversion cv = new contentversion();
        cv.contentlocation = 'S';
        cv.PathOnClient = 'sample.'+CL_ContentDocumentLinkTrg.mailExtensionList.get(0);
        cv.Title = 'sample';
        cv.VersionData = Blob.valueOf('sample file');
        insert cv;

        // ContentDocument Id 取得
        contentversion cvDocument = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl = new ContentDocumentLink();
        cdl.LinkedEntityId = record.Id;
        cdl.ContentDocumentId = cvDocument.ContentDocumentId;
        insert cdl;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        delete cdl;
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('無', result.SofuMailUmu__c);
    }

    @isTest static void afterDeleteTest03() {
        /* ＝＝＝＝＝＝テストデータ準備＝＝＝＝＝＝ */
        // 業務オブジェクトテストデータ取得
        Travel_Request__c record = [SELECT Id FROM Travel_Request__c];

        // 添付ファイル1作成
        contentversion cv1 = new contentversion();
        cv1.contentlocation = 'S';
        cv1.PathOnClient = 'sample01.'+CL_ContentDocumentLinkTrg.mailExtensionList.get(0);
        cv1.Title = 'sample01';
        cv1.VersionData = Blob.valueOf('sample file01');
        insert cv1;
        // 添付ファイル2作成
        contentversion cv2 = new contentversion();
        cv2.contentlocation = 'S';
        cv2.PathOnClient = 'sample02.'+CL_ContentDocumentLinkTrg.mailExtensionList.get(0);
        cv2.Title = 'sample02';
        cv2.VersionData = Blob.valueOf('sample file02');
        insert cv2;

        // ContentDocument Id 取得
        contentversion cvDocument01 = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample01' AND IsLatest=True];
        contentversion cvDocument02 = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Title='sample02' AND IsLatest=True];

        // ContentDocumentLinkテストデータ作成
        ContentDocumentLink cdl1 = new ContentDocumentLink();
        cdl1.LinkedEntityId = record.Id;
        cdl1.ContentDocumentId = cvDocument01.ContentDocumentId;
        insert cdl1;
        ContentDocumentLink cdl2 = new ContentDocumentLink();
        cdl2.LinkedEntityId = record.Id;
        cdl2.ContentDocumentId = cvDocument02.ContentDocumentId;
        insert cdl2;

        // 業務オブジェクト.送付メール有無にNULLを設定する
        record.SofuMailUmu__c = '';
        update record;

        /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
        Test.startTest();
        delete [SELECT Id FROM ContentDocument where Id =:cvDocument01.ContentDocumentId];
        Test.stopTest();

        /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */
        Travel_Request__c result = [SELECT Id,SofuMailUmu__c FROM Travel_Request__c Limit 1];
        System.assertEquals('有', result.SofuMailUmu__c);
    }
}
```

以上。