1

I am receiving an Error in my Test class, but am unsure of the reason why. Here is the Error:

Exception: Update failed. First exception on row 0 with id a0i4C000000HfieQAC; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, TABLoan_beforeupdate: execution of BeforeUpdate caused by: System.NullPointerException: Attempt to de-reference a null object

Class.TestTABLoan_beforeupdate.testTABbeforeupdate: line 30, column 1

Trigger.TABLoan_beforeupdate: line 9, column 1: []

Below is the Test Class:

@isTest
public class TestTABLoan_beforeupdate {
    static testMethod void testTABbeforeupdate() {
        //Create records to test
        Account myAccount = new Account();
        myAccount.Name = 'My Awesome Account';
        myAccount.Industry  = 'Energy';
        myAccount.Type = 'Association';
        myAccount.RecordTypeId = [Select Id,SobjectType,Name From RecordType WHERE Name ='Business' and SobjectType ='Account'  limit 1].Id;
        insert myAccount; 

        Opportunity myopportunity = new Opportunity();
        myopportunity.Name = 'My Opportunity ties to a lead.';
        myopportunity.Account = myAccount;
        myopportunity.StageName = 'Applicant'; 
        myopportunity.CloseDate = Date.today();
        insert myopportunity;     

        LLC_BI__Loan__c myLoan = new LLC_BI__Loan__c();
        myLoan.Name = 'This Lead has an Opportunity,';
        myLoan.Opportunity_Source__c = myopportunity.Id;
        myLoan.LLC_BI__Principal_Balance__c = 3000000;
        myLoan.LLC_BI__Account__c = myAccount.Id;
        myLoan.LLC_BI__Product_Line__c = 'ABL';
        myLoan.LLC_BI__Product_Type__c = 'ABL';
        myLoan.LLC_BI__Product__c = 'Other';
        insert myLoan;

        myLoan.LLC_BI__Principal_Balance__c = 250000;
        update myLoan;

        myopportunity = [SELECT Id, PrincipalBalance__c From Opportunity LIMIT 1];
        System.assertEquals(myopportunity.PrincipalBalance__c, 250000);
    }
}

And here is the trigger I am testing:

trigger TABLoan_beforeupdate on LLC_BI__Loan__c (before update) {

    List<LLC_BI__Loan__c> loans = new List<LLC_BI__Loan__c>();
    for (LLC_BI__Loan__c l : Trigger.new){
        // Access the "old" record by its ID in Trigger.oldMap
        LLC_BI__Loan__c oldl = Trigger.oldMap.get(l.id);
        // Check to see if loan has principal balance and Opportunity source
        if ((oldl.LLC_BI__Principal_Balance__c != l.LLC_BI__Principal_Balance__c) && (l.Opportunity_Source__c != null )) {
            l.Opportunity_Source__r.PrincipalBalance__c = l.LLC_BI__Principal_Balance__c;
            loans.add(l);   
        }
    }
    update loans;
}
2
  • Can you post the stack track for the error you are receiving?
    – SFDC Neuf
    Commented Jan 31, 2017 at 21:27
  • 1
    On the trigger, you probably don't need the update DML. Commented Jan 31, 2017 at 21:37

2 Answers 2

2

From the look of it, your error is pointing to this particular line in your trigger:

l.Opportunity_Source__r.PrincipalBalance__c = l.LLC_BI__Principal_Balance__c;

You're trying to update a field on a related object, which doesn't work (as you've found out).

Trigger context variables do not contain related data (fields on related objects), only the fields for the object that a given trigger is defined on (LLC_BI__Loan__c in your case).

A few changes you should make to get things working:

Change your trigger to be an after update trigger

Salesforce recommends using an after trigger when you are setting/updating fields on an object that is different than the one the trigger is defined on.

You're also not updating any fields on any LLC_BI__Loan__c records, so there's no benefit to using a 'before' trigger here anyway.

Make use of your ability to set an Id in an sObject constructor

Normally, if you want to update a record, you'd query for that record, make changes to it, and then DML update it.

If you have the Id of the record you want to update, you don't need to query at all!

In your case, updating the related Opportunity_Source__c (just guessing that it isn't a standard Opportunity) would look something like this

 for (LLC_BI__Loan__c l : Trigger.new){
    LLC_BI__Loan__c oldl = Trigger.oldMap.get(l.id);
    if ((oldl.LLC_BI__Principal_Balance__c != l.LLC_BI__Principal_Balance__c) && (l.Opportunity_Source__c != null )) {
        // Use the sObject constructor to set the Id
        // This allows us to update a record without querying for it first.
        Opportunity_Source__c oppSourceForUpdate = new Opportunity_Source__c(
            // Inside this constructor, we use commas to separate fields.
            // Do not use semicolons in here!
            Id = l.Opportunity_Source__c,
            PrincipalBalance__c = l.LLC_BI__Principal_Balance__c
        );

        // This is a list, and would need to be defined outside of your loop
        recordsToUpdate.add(oppSourceForUpdate); 
    }
}
// Outside of all loops, safe to perform DML
3

I believe this is because you are referencing a field across a relationship in your trigger.

l.Opportunity_Source__r.PrincipalBalance__c

l.Opportunity_Source__r ... will not have any field values in it, the trigger only lazy-loads referenced fields on the actual objects going through the trigger.

You will need to collect a Set<Id> of all the Opportunity_Source__c records you need, load them into a Map<Id, sObject> so you can then get them back when you need to reference them in your loop. (this approach is a best practise for bulk-friendly triggers).

You must log in to answer this question.

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