I have created a trigger functionality on after insert of content document link, trigger functionality is working as expecting.

But when i have written a test class to insert test record for ContentDocumentLink object to get code coverage, the LinkedEntityId is always taking a user id, i want a custom object record id in this place. Because i have a if condition for to check based prefix.

Below is my class and test class.

public with sharing class X{ 
    public void y(List<ContentDocumentLink> contentDocLinkLst){
        //Load Request Form Keyprfix
        Schema.DescribeSObjectResult GetObjkeyPrefix = A__C.sObjectType.getDescribe();
        String StrkeyPrefix = GetObjkeyPrefix.getKeyPrefix();
        List<A__C> ALst  = new List<A__C>();
        for(ContentDocumentLink link: contentDocLinkLst){
            string strparentid = link.LinkedEntityId;
            if(strparentid.substring(0,3) == StrkeyPrefix){
                A__C updrec = new A__C();
                updrec.Id = link.LinkedEntityId;  
        //Updating BIC Result object records
            Update ALst;

Test class

private class ContentDocumentLinkActionTest{
//Inserting list of A__C object records
        List<A__C> ALst = new List<A__C>();
        A__C br;
        for(integer i=0; i<=5; i++){
            br = new A__C();
            br.BIC_Name__c = bic.Id;
            br.BIC_Question__c = ques.Id;
            br.BIC_Section__c = sec.Id;
        insert ALst;
        system.assert(ALst[0].id != null, true);  

        //Inserting content document link record
        ContentVersion contentVersion = new ContentVersion(
            Title = 'Penguins',
            PathOnClient = 'Penguins.jpg',
            VersionData = Blob.valueOf('Test Content'),
            IsMajorVersion = true
        insert contentVersion;   
        List<ContentDocument> documents = [SELECT Id, Title, LatestPublishedVersionId FROM ContentDocument];
        //create ContentDocumentLink  record 

        ContentDocumentLink cdl = New ContentDocumentLink();
        cdl.LinkedEntityId = ALst[0].id;
        cdl.ContentDocumentId = documents[0].Id;
        cdl.shareType = 'V';
        insert cdl;

public with sharing class ContentDocumentLinkAction { 

    // Initialize static booleans to track if this is the first time a specific
    // Trigger Action has been called within the current Execution Context.
    public  static  boolean onBeforeInsert_FirstRun   = true;
    public  static  boolean onBeforeUpdate_FirstRun   = true;
    public  static  boolean onBeforeDelete_FirstRun   = true;
    public  static  boolean onAfterInsert_FirstRun    = true;
    public  static  boolean onAfterUpdate_FirstRun    = true;
    public  static  boolean onAfterDelete_FirstRun    = true;
    public  static  boolean onAfterUndelete_FirstRun  = true;
    public  static UpdateBICResultOnFileUpload updateBICResult = new UpdateBICResultOnFileUpload();
    Public static final string strUpdate = 'Update'; 

    // Instance variables that will hold information about specific runs through
    // the trigger.
    private         integer batchSize                  = 0;
    public          boolean isTriggerContext           {get{return (isTriggerContext == null) ? false : isTriggerContext;} private set;}    // Returns TRUE if the execution context was begun via the Standard UI, ie. NOT Visualforce, API call, etc.

    // Constructor
    public ContentDocumentLinkAction(boolean isTriggerContextParam, integer batchSizeParam) {

        isTriggerContext  = isTriggerContextParam;
        batchSize         = batchSizeParam;

    * onBeforeInsert() Handler.
    * #Describe the functional logic of this trigger action handler.#
    * @param    newObjects          List of SObjects that are about to be inserted.
    * @return   void
    * @see      #List any service classes referenced by this action handler#
    public void onAfterInsert(List<SObject> newObjects) {
        if(onAfterInsert_FirstRun) {
            // PREVENT RECURSION
            onAfterInsert_FirstRun = false; 
            //Updating BIC result object fields

The if condition logic is not at all covering.

Can you please help me on this.

  • Did u try to wrap your test code inside System.runAs() Profile p = [SELECT Id FROM Profile WHERE Name='System Administrator']; User u = new User(Alias = 'newUser', Email='[email protected]', EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US', LocaleSidKey='en_US', ProfileId = p.Id, TimeZoneSidKey='America/Los_Angeles', UserName='[email protected]',Currency__c = 'INR'); System.runAs(u) { //put your test logic here. } Commented Oct 10, 2018 at 12:21
  • What is the purpose of the static variable bicresultId? What logic creates the list contentDocLinkLst? If you debug the input into the function y(), what do you see exactly?
    – David Reed
    Commented Oct 10, 2018 at 12:26
  • I tried to put a value for this variable from test class, but that is not working for me. This logic we are calling from contentdocumentlink after insert trigger. when i put a log in test class excution. |DEBUG|###contentDocLinkLst::(ContentDocumentLink:{Id=06A1F0000006TDQUA2, LinkedEntityId=0051F000001rRe6QAE, ContentDocumentId=0691F0000005pLkQAI, IsDeleted=false, SystemModstamp=2018-10-10 12:37:28, ShareType=I, Visibility=AllUsers}) this is the debug i got. Here if u observe LinkedEntityId=0051F000001rRe6QAE is user id i am expecting A__c record id here. Commented Oct 10, 2018 at 12:50
  • Yes, that's to be expected - the ContentDocument is automatically shared to its owner, the running user. You should also see the ContentDocumentLink you insert. Can you edit your trigger code into your question? Are you perhaps using a static Boolean recursion guard?
    – David Reed
    Commented Oct 10, 2018 at 13:04
  • 1
    Please show your trigger code. I am fairly confident that the recursion check is the problem.
    – David Reed
    Commented Oct 10, 2018 at 13:07

1 Answer 1


Your problem is your naive recursion guard, because this trigger must execute twice in the course of the test transaction to operate correctly.

if(onAfterInsert_FirstRun) {
    onAfterInsert_FirstRun = false; 
    //Updating BIC result object fields

This code is executed once when you insert your ContentDocument in your test, because the system at that point automatically inserts a ContentDocumentLink to share the ContentDocument to its owner, your test running user. That's the record you're seeing in your debug logs.

Then, when you insert your ContentDocumentLink to share the file to the A__c record, your trigger code does not execute, because onAfterInsert_FirstRun is false - the trigger already ran on the earlier DML operation.

There are many, many situations in which this simplistic recursion guard will not work. A static Set of already-processed records works better, but still has some issues. However, it's not clear to me why you need recursion defense on this after insert operation at all.

In any case, that's your problem. You need to fix your recursion guard, and your test will probably pass - the code looks good to me. You do need to be writing some assertions to make this a true unit test, however.

  • Now i understand, it's a very good discussion. If the recursion is the problem when i am inserting a file under A__c record there it is firing twice one for user another for A__c. There also it should run only once right as per recursion guard, why in test class alone it running only once? Commented Oct 10, 2018 at 13:21
  • The trigger is not recursing. Your recursion guard is blocking it from running when it should run.
    – David Reed
    Commented Oct 10, 2018 at 13:22
  • 1
    Yes the problem is with the recursive guard, i changed it then able to cover the test class. Thanks for your valuable time and suggestions. Commented Oct 10, 2018 at 14:04

You must log in to answer this question.

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