2

I have written a Trigger for ContentDocumentLink and I am trying to write a test class but using Test Class Trigger is not getting covered.

Trigger :

trigger contentDocumentLinkTrigger on ContentDocumentLink (after insert) {
    if(contentDocumentLinkTriggerHandler.isExecute)
        contentDocumentLinkTriggerHandler.processOnInsert(trigger.new);
}

Handler :

public with sharing class contentDocumentLinkTriggerHandler {
    public static boolean isExecute = true;
    public static void processOnInsert(list<ContentDocumentLink> newList) {
        list<ContentDocumentLink> contentList = new list<ContentDocumentLink>();
        set<id> accId = new set<id>();
        map<id,list<ContentDocumentLink>> parentContentMap = new map<id,list<ContentDocumentLink>>();
        set<id> contId = new set<id>();
        set<id> opptyId = new set<id>();
        for(ContentDocumentLink nt : newList){
            string pId = string.valueOf(nt.linkedentityid).substring(0,3);
            if(pid == '001'){
                accId.add(nt.linkedentityid);
            }
            if(pid == '003'){
                contId.add(nt.linkedentityid);  
            }
            if(pid == '006'){
                opptyId.add(nt.linkedentityid);
            }
            if(parentContentMap.containsKey(nt.linkedentityid))
                parentContentMap.get(nt.linkedentityid).add(nt);
            else
                parentContentMap.put(nt.linkedentityid,new list<ContentDocumentLink>{nt});
        }   
        if(!accId.isEmpty()){
            for(Account acc : [select id,(select id from contacts),(select id from opportunities) from Account where id in : accId]){
                if(parentContentMap.containsKey(acc.id)){
                    for(ContentDocumentLink nt : parentContentMap.get(acc.id)){
                        for(Contact ct : acc.contacts){
                            ContentDocumentLink nt1 = nt.clone(false); 
                            nt1.linkedentityid = ct.id;
                            contentList.add(nt1);
                        }
                        for(Opportunity opp : acc.opportunities){
                            ContentDocumentLink nt1 = nt.clone(false); 
                            nt1.linkedentityid = opp.id;
                            contentList.add(nt1);
                        }
                    }
                }
            }
        }

        if(!contId.isEmpty()){
            map<id,id> conAccMap = new map<id,id>();
            for(Contact cont : [select accountId from Contact where id in : contId]){
                conAccMap.put(cont.accountId,cont.id);
            }
            for(Account acc : [select id,(select id from contacts),(select id from opportunities) from Account where id in : conAccMap.keySet()]){
                if(parentContentMap.containsKey(conAccMap.get(acc.id))){
                    for(ContentDocumentLink nt : parentContentMap.get(conAccMap.get(acc.id))){
                        ContentDocumentLink nt2 = nt.clone(false); 
                        nt2.linkedentityid = acc.id;
                        contentList.add(nt2);
                        for(Contact ct : acc.contacts){
                            ContentDocumentLink nt1 = nt.clone(false); 
                            nt1.linkedentityid = ct.id;
                            if(conAccMap.get(acc.id) != ct.id)
                                contentList.add(nt1);
                        }
                        for(Opportunity opp : acc.opportunities){
                            ContentDocumentLink nt1 = nt.clone(false); 
                            nt1.linkedentityid = opp.id;
                            contentList.add(nt1);
                        }
                    }
                }
            }
        }

        if(!opptyId.isEmpty()){
            map<id,id> optyAccMap = new map<id,id>();
            for(Opportunity oppty : [select accountId from Opportunity where id in : opptyId]){
                optyAccMap.put(oppty.accountId,oppty.id);
            }
            for(Account acc : [select id,(select id from contacts),(select id from opportunities) from Account where id in : optyAccMap.keySet()]){
                if(parentContentMap.containsKey(optyAccMap.get(acc.id))){
                    for(ContentDocumentLink nt : parentContentMap.get(optyAccMap.get(acc.id))){
                        ContentDocumentLink nt2 = nt.clone(false); 
                        nt2.linkedentityid = acc.id;
                        contentList.add(nt2);
                        for(Contact ct : acc.contacts){
                            ContentDocumentLink nt1 = nt.clone(false); 
                            nt1.linkedentityid = ct.id;

                            contentList.add(nt1);
                        }
                        for(Opportunity opp : acc.opportunities){
                            ContentDocumentLink nt1 = nt.clone(false); 
                            nt1.linkedentityid = opp.id;
                            if(optyAccMap.get(acc.id) != opp.id)
                                contentList.add(nt1);
                        }
                    }
                }
            }
        }
        if(contentList.size() > 0){
            isExecute = false;
            insert contentList;
        }
    }
}

Test Class :

@isTest
private class contentDocumentLinkTriggerTest
{
    @isTest
    static void itShould()
    {
        Account acc = new Account(name='test acc');
        insert acc;
        Contact con = new Contact(lastname='test cont',accountid=acc.id);
        insert con;
        Opportunity opp = new Opportunity(name='testoppty',AccountId=acc.id,stageName='Qualification',closedate=system.today());
        insert opp;

        ContentVersion content=new ContentVersion(); 
            content.Title='Header_Picture1'; 
            content.PathOnClient='/' + content.Title + '.jpg'; 
            Blob bodyBlob=Blob.valueOf('Unit Test ContentVersion Body'); 
            content.VersionData=bodyBlob; 
            //content.LinkedEntityId=sub.id;
            content.origin = 'H';
        insert content;
        ContentDocumentLink contentlink=new ContentDocumentLink();
            contentlink.LinkedEntityId=acc.id;
            contentlink.contentdocumentid=[select contentdocumentid from contentversion where id =: content.id].contentdocumentid;
            contentlink.ShareType = 'V';
            test.starttest();
        insert contentlink;
test.stoptest();

    }
}
1
  • 1
    coding tip: instead of if(pid == '001'), use if (nt.linkedentityid.getSobjectType() == Account.SObjectType) - future-proofed and self-documenting.
    – cropredy
    Commented Jul 12, 2016 at 5:52

4 Answers 4

5

Here is My sample code of Trigger,Class and Testclass

Trigger :-

trigger Attachment on ContentDocumentLink (after insert, after delete) 
{
   AttachmentHandler ah = new AttachmentHandler();

        if(trigger.isInsert)
        {
            ah.handleOnInsert(trigger.new);       
        }
        if(trigger.isDelete)
        {
            ah.handleOnDelete(trigger.old); 
        } 


}

Apex Class :-

public class AttachmentHandler 
{
    public void handleOnDelete(List<ContentDocumentLink> newList) //This Function work on Delete Attachment related to opportunity and according to that it update the opportunity fields
    {

            List<ID> oppIDs = new List<ID>();
            List<Opportunity> oppsToUpdate = new List<Opportunity>();
            Map <Id,List<ContentDocumentLink>> mapAttByOpp = new  Map <id,List<ContentDocumentLink>>();

            for(ContentDocumentLink a: newList)
            {
                oppIDs.add(a.LinkedEntityId);
            }

            List<ContentDocumentLink> allAtt = [Select id, LinkedEntityId from ContentDocumentLink where LinkedEntityId =:oppIDs];

            for(ContentDocumentLink a : allAtt)
            {

                if( !mapAttByOpp.containsKey(a.LinkedEntityId) )
                {
                    mapAttByOpp.put(a.LinkedEntityId, new List <ContentDocumentLink>());
                }
                mapAttByOpp.get(a.LinkedEntityId).add(a);
            }

            for(ContentDocumentLink a : newList)
            {
                string temp=a.LinkedEntityId;
                if(temp.startswith('006'))
               {
                    Opportunity o = new Opportunity(id=a.LinkedEntityId);
                    if(mapAttByOpp.get(a.LinkedEntityId) == null )
                    {

                        o.Attachment__c = false;
                        o.Doc_Status__c ='Pending';
                        oppsToUpdate.add(o);
                    }
                }
            }

            if(oppsToUpdate.size()>0)
                update oppsToUpdate;

    }

    public void handleOnInsert(List<ContentDocumentLink> newList) //This Function work on Insert Attachment related to opportunity and according to that it update the opportunity fields
    {
        List<Opportunity> oppsToUpdate = new List<Opportunity>();

        for(ContentDocumentLink a: newList)
        {
           string temp=a.LinkedEntityId;
                if(temp.startswith('006'))
               {
                    Opportunity o = new Opportunity(id=a.LinkedEntityId);
                    if(!o.Attachment__c)
                    {
                        o.Attachment__c= true;
                        o.Doc_Status__c ='Completed';
                        oppsToUpdate.add(o);
                    }
                }
        } 

        if(oppsToUpdate.size()>0)
            update oppsToUpdate;
    } 


}

Test Class :-

@isTest(seealldata=true)
public class TestAttachmentHandler 
{
    static testMethod void validateHelloWorld()
    {
        opportunity opp=[select ID from opportunity Limit 1];
        Blob beforeblob=Blob.valueOf('Unit Test Attachment Body');

        ContentVersion cv = new ContentVersion();
        cv.title = 'test content trigger';      
        cv.PathOnClient ='test';           
        cv.VersionData =beforeblob;          
        insert cv;         

        ContentVersion testContent = [SELECT id, ContentDocumentId FROM ContentVersion where Id = :cv.Id];

        ContentDocumentLink contentlink=new ContentDocumentLink();
        contentlink.LinkedEntityId=opp.id;
        contentlink.ShareType= 'V';
        contentlink.ContentDocumentId=testcontent.ContentDocumentId;

        insert contentlink;

        delete contentlink;

    }

}
2

I have tried this approach and it worked and gives the coverage 95% to the class.

Created separate test methods for account, contact and opportunity and run the test.

Find the updated test class as follows:

@isTest
private class contentDocumentLinkTriggerTest{
@isTest
static void itShould()
{
    Account acc = new Account(name='test acc');
    insert acc;
    Contact con = new Contact(lastname='test cont',accountid=acc.id);
    insert con;
    Opportunity opp = new Opportunity(name='testoppty',AccountId=acc.id,stageName='Qualification',closedate=system.today());
    insert opp;

    ContentVersion content=new ContentVersion(); 
        content.Title='Header_Picture1'; 
        content.PathOnClient='/' + content.Title + '.jpg'; 
        Blob bodyBlob=Blob.valueOf('Unit Test ContentVersion Body'); 
        content.VersionData=bodyBlob; 
        //content.LinkedEntityId=sub.id;
        content.origin = 'H';
    insert content;
    ContentDocumentLink contentlink=new ContentDocumentLink();
        contentlink.LinkedEntityId=acc.id;
        contentlink.contentdocumentid=[select contentdocumentid from contentversion where id =: content.id].contentdocumentid;
        contentlink.ShareType = 'V';
        test.starttest();
    insert contentlink;
}   
@isTest
static void itShould2()
{   
    Account acc = new Account(name='test acc');
    insert acc;
    Contact con = new Contact(lastname='test cont',accountid=acc.id);
    insert con;
    Opportunity opp = new Opportunity(name='testoppty',AccountId=acc.id,stageName='Qualification',closedate=system.today());
    insert opp;
    ContentVersion content2=new ContentVersion(); 
        content2.Title='Header_Picture1'; 
        content2.PathOnClient='/' + content2.Title + '.jpg'; 
        Blob bodyBlob=Blob.valueOf('Unit Test ContentVersion Body'); 
        content2.VersionData=bodyBlob; 
        //content2.LinkedEntityId=sub.id;
        content2.origin = 'H';
    insert content2;

    ContentDocumentLink contentlink2=new ContentDocumentLink();
        contentlink2.LinkedEntityId=con.id;
        contentlink2.contentdocumentid=[select contentdocumentid from contentversion where id =: content2.id].contentdocumentid;
        contentlink2.ShareType = 'V';
        //test.starttest();
    insert contentlink2;
}

@isTest
static void itShould3()
{
    Account acc = new Account(name='test acc');
    insert acc;
    Contact con = new Contact(lastname='test cont',accountid=acc.id);
    insert con;
    Opportunity opp = new Opportunity(name='testoppty',AccountId=acc.id,stageName='Qualification',closedate=system.today());
    insert opp;

    ContentVersion content3=new ContentVersion(); 
        content3.Title='Header_Picture1'; 
        content3.PathOnClient='/' + content3.Title + '.jpg'; 
        Blob bodyBlob=Blob.valueOf('Unit Test ContentVersion Body'); 
        content3.VersionData=bodyBlob; 
        //content3.LinkedEntityId=sub.id;
        content3.origin = 'H';
    insert content3;

    ContentDocumentLink contentlink3=new ContentDocumentLink();
        contentlink3.LinkedEntityId=opp.id;
        contentlink3.contentdocumentid=[select contentdocumentid from contentversion where id =: content3.id].contentdocumentid;
        contentlink3.ShareType = 'V';
        //test.starttest();
    insert contentlink3;

    //test.stoptest();
   }
}
1

The issue was the API Version of trigger. I was working on 34.0 and as I changed 37.0, my test class is working.

Thanks everyone for the answers.

0
1

I had this issue as well, and as Jaideep said above the issue is the API version. There was apparently a bug in version 34.0 that was causing some ContentDocumentLink triggers to not fire. The one thing I would add is specifics on how exactly to fix it.

You'll need to edit the xml document of your test class (or whatever class it is that is actually doing the insert / delete of the ContentDocumentLink record(s). So if your class file is ContentDocumentLinkTests.cls you'll edit ContentDocumentLinkTests.cls-meta.xml.

Set the apiVersion property to anything past 34.0. For me the most recent version was 39.0 so that yields an xml file like this:

<?xml version="1.0" encoding="UTF-8"?>
    <ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>39.0</apiVersion>
    <status>Active</status>
</ApexClass>

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .