2

I am writing a test class for my code and am running into an issue that is annoying me. So I was wondering if there is any way to do this.

I have an Apex class with some functionality that I am Unit Testing, let's assume it is defined something like this:

public class HelperClass {
    public static Object someFunction(Parent__c parentObject) {}
}

The parentObject SObject input is expected to be provided in such a way, that it will contain the parent record as well as the child records so they are passed as one input and stay together. This is done by the calling methods by using a relationship query similar to the following way:

Parent__c parentObject = [SELECT Id, Name, (SELECT Id, Name FROM Children__r) WHERE Id = :recId];

Parent__c and Child__c are both configuration objects so for testing I have a pretty good idea what they should typically look like to fit my test cases. I want to see if it is possible to skip doing the DML as I want fast test classes and it are quite a few records that I want to create for all assertions. So I wanted to build the test data as below:

@IsTest
private static void testHelperClassSomeFunction() {    
    // define children records
    List<Child__c> testChildren = new List<Child__c>{new Child__c(Name = 'Test Child Record')};    
    
    // define parent record
    Parent__c testParent = new Parent__c(Name = 'Test Parent Record');
    // add children records to the relationship:
    testParent.Children__r = testChildren;

    Object testOutput = HelperClass.somefunction(testParent);    
    // asserts here    
}

However, if I do this, I get the error

Field is not writeable: Parent__c.Children__r

I know that I can insert the children and the parent and then use a relationship query. As mentioned I want to keep from doing the DML and requerying the records as this would otherwise be needlessly slow and this will be repeated in other tests as well.

Plus, I just want to know if there is any way around this... So is there any way to build the object as described above in Apex without fetching the data using a query?

1
  • Welcome to SFSE! This is a great first question. I know I've tried to do this in the past, but I don't remember if I ever got it working. Test.loadData() can be used to set (some) otherwise read-only fields, but I don't know whether or not it would work. I'll aim to do some research if I can find some time later today.
    – Derek F
    Oct 8, 2020 at 11:36

2 Answers 2

2

You can't do this "out of the box" using the conventional approach of creating the SObjects in-memory and linking them up manually due to this very annoying limitation in managing MD children relationships.

If you want to avoid DML, the best way to achieve this is by using an approach such as that employed in the SObject Fabricator.

This works by building "proxy objects" (just POTATOs - Plain Old Transactional Apex Transient Objects) that generate JSON that matches that of serialized SObjects, and thus can be de-serialized into real SObjects, all in-memory only.

0

I don't know what actions you are performing in the method, but I am assuming that you are modifying or using both parent and child records. I don't think there is any shortcut to do that, you have to insert both parent and child records. You don't have to create data in each test method, you can use @testSetup annotation to create test data in single method, something like this

@testSetup
private static void testDataSetup() {   
    // define parent record
    Parent__c testParent = new Parent__c(Name = 'Test Parent Record'); 
    insert testParent;
    // define children records. 
    List<Child__c> testChildren = new List<Child__c>{new Child__c(Parent__c=testParent.Id, Name = 'Test Child Record')};    
    insert testChildren;
}

I am assuming relationship field Name on child object is Parent__c

You can query data in your test methods and pass it to your class method.

@IsTest
private static void testHelperClassSomeFunction() {    
    Parent__c parentObject = [SELECT Id, Name, (SELECT Id, Name FROM Children__r) WHERE Id = :recId];

    Object testOutput = HelperClass.somefunction(parentObject);    
    // asserts here    
}

Creating/Updating relationship is not possible on parent object. We have to insert parent(master) record first and then populate relationship field on child record.

Field is not writeable: Parent__c.Children__r

You must log in to answer this question.

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