1

We have been using FFLIB(Apex commons) in our org.I have been trying to write a test case for a Content Document Link (Salesforce Files)Domain layer But i have been getting the error : "System.NullPointerException: Argument cannot be null." I am new to the library and now that i have tried few things , i am assuming it is something to do with ContentDocumentLink. Can somebody please help me resolve this.I want to adopt the AEP and Apex mocks and not go back to writing usual test cases.

My class:

public class XYZ_DOM_ContentDocumentLinks extends fflib_SObjectDomain implements XYZ_DOM_IContentDocumentLinks{
    

    public static XYZ_DOM_IContentDocumentLinks  newInstance(List<SObject> sObjectList) {
        return (XYZ_DOM_IContentDocumentLinks) XYZ_Application.Domain.newInstance(sObjectList);
    }

    
    public Map<Id, String> getBodyAsStringByLinkedEntityId (){
        Map <Id, String> bodyAsString = new Map<Id, String>();
        for(ContentDocumentLink file : (List<ContentDocumentLink>) Records){
            Blob FileBody = file.ContentDocument.LatestPublishedVersion.VersionData;
            String attachmentAsString = FileBody.toString();
            bodyAsString.put(file.LinkedEntityId, attachmentAsString);
        }
        return bodyAsString;
    }

public XXYZ_DOM_ContentDocumentLinks(List<SObject> records) {
        super(records);
    }

    public class Constructor implements fflib_SObjectDomain.IConstructable {
        public fflib_SObjectDomain construct(List<SObject> records) {
            return new XXYZ_DOM_ContentDocumentLinks(records);
        }
    }

}

My Test Class:

// Given
        ContentDocumentLink record = new ContentDocumentLink(
            Id = fflib_IDGenerator.generate(ContentDocumentLink.SObjectType)
            );
    
    List<ContentDocumentLink> testContentDocumentLinkRecords = new List<ContentDocumentLink> { record };
 

    // When
    XYZ_DOM_IContentDocumentLinks contentDocumentLinks = XYZ_DOM_ContentDocumentLinks.newInstance(testContentDocumentLinkRecords);

        contentDocumentLinks.getBodyAsStringByLinkedEntityId();

    // Then
        System.assertEquals(1, contentDocumentLinks.getBodyAsStringByLinkedEntityId().size());

It's line 13 which is erroring out : Class.XYZ_DOM_ContentDocumentLinks.getBodyAsStringByLinkedEntityId: line 13. This belongs to the Domain class: String attachmentAsString = FileBody.toString();

Stack Trace: -- | --

Class | XYZ_DOM_ContentDocumentLinks_Test

Method Name | testGetBodyAsStringByLinkedEntityId

Pass/Fail | Fail

Error Message | System.NullPointerException: Argument cannot be null.

Stack Trace |

Class.XYZ_DOM_ContentDocumentLinks.getBodyAsStringByLinkedEntityId: line 13, column1

Class.IRR_DOM_ContentDocumentLinks_Test.testGetBodyAsStringByLinkedEntityId: line 33, column 1

8
  • Have you identified the line on which the NPE happens? The call stack should show which line in your code suffers this exception even if it is thrown from within a call you make to the fflib.
    – Phil W
    Commented Apr 15, 2021 at 9:56
  • @PhilW Yes, its line 13 Class.XYZ_DOM_ContentDocumentLinks.getBodyAsStringByLinkedEntityId: line 13, column 1...Which is this from the class: ``` String attachmentAsString = FileBody.toString(); ``` Commented Apr 15, 2021 at 10:01
  • Can you edit the question to add the necessary details so it is nice and clear?
    – Phil W
    Commented Apr 15, 2021 at 10:13
  • if you are trying to use apexmocks then you need to use edit and show how you are setting up the mock Domain class; see also Why are my Apex Mocks not working
    – cropredy
    Commented Apr 15, 2021 at 16:25
  • Thanks @cropredy. I edited to show my entire domain class, if that's what you are asking.I am thinking, it's something to do when I create ContentDocumentLink record but there is no content/versiondata , but I am unable to understand how to create a wholesome record with mocks. Commented Apr 15, 2021 at 16:41

1 Answer 1

1

in my opinion, the best tool to mock SObjects and their relationships when there are non-writeable fields is the SObject Fabricator by @mattaddy on GitHub.

So, this means you will have the following:

// given mock CDLs
        
ContentDocumentLink[] mockCDLs = new List<ContentDocumentLink> {
  (ContentDocumentLink) new sfab_FabricatedSObject( ContentDocumentLink.class )
   .set(ContentDocumentLink.Id,fflib_IDGenerator.generate(ContentDocumentLink.SObjectType))
   .set(ContentDocumentLink.LinkedEntityId,fflib_IDGenerator.generate(Opportunity.SObjectType))
   .set('ContentDocument.LatestPublishedVersion.Id',fflib_IDGenerator.generate(ContentVersion.SObjectType))
   .toSobject(),
          ... next CDL
}

// workaround for Blobs which don't serialize/deserialize on sobjects properly
mockCDLs[0].ContentDocument.LatestPublishedVersion.VersionData = Blob.valueOf( 'abc' ); 


// given domain class

XYZ_DOM_IContentDocumentLinks domain = XYZ_DOM_IContentDocumentLinks.newInstance(mockCDLs);

//  when getBodyAsStringByLinkedEntityId

Map<Id,String> results = domain.getBodyAsStringByLinkedEntityId();

// Then verify
...

Be sure your Interface XYZ_DOM_IContentDocumentLinks includes an entry for

Map<Id,String> getBodyAsStringByLinkedEntityId();
9
  • So you mean there is no way to 'mock' CDL records with fflib, so either i have to go 'DML' way or use 'SObject Fabricator '? If yes,which is the preferable way?I am a novice hence little apprehensive of using so many third party libs in org and create dependencies. Commented Apr 16, 2021 at 3:35
  • There is an sobject mocking class in fflib but I find it clunky to use when dealing with relationships and collections of mocked objects. My org is a heavy fflib org and adding sfab was a nice complement. You only need to use sfab when mocking objects with unwriteable fields. Of course, you can also use Json.serialize/deserialize from strings and maps of strings. Others may suggest that approach as their answer. Sfab uses Json.serialize/deserialize under the covers but I find the expressive power of the builder pattern handy.
    – cropredy
    Commented Apr 16, 2021 at 3:42
  • This is the error that I am getting: Error Message System.JSONException: Cannot deserialize instance of <unknown> from VALUE_STRING value YWJj or request may be missing a required field .I also changed Blob.valueOf('abc') instead of instanceOf.InstanceOf is throwing error : Method does not exist or incorrect signature: void newInstance(String) from the type Blob Commented Apr 16, 2021 at 8:11
  • Whatever I try,it just says System.JSONException: Cannot deserialize instance of <unknown> from VALUE_STRING:( Commented Apr 16, 2021 at 9:00
  • 1
    updated my answer thanks to @RobBaillie workaround
    – cropredy
    Commented Apr 20, 2021 at 15:02

You must log in to answer this question.

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