function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
RonVRonV 

Trigger Update Parent when child is inserted. Test Class not working

I am trying to write a trigger to update a couple of fields in a parent record when a child record is created.
This is my first Apex class and I am struggling.

Let me apologise for the length of this post, but I want to provide as much information as possible.

Here is the scenario.

We have the following custom objects:

 

Machine__c
Which (among others) has the following custom fields:

Model__c (Lookup to a custom Model__c object, which is a parent to Machine__c)
Est_Cust_Name__c (String)
Delivery_Date__c (Date)

Machine_Ownership__c
This is a child field of Machine__C. A Machine may have 0,1, or many Machine_Ownership records.
It has the following custom fields:

Customer__c (Lookup to Account object for Customer)
Dealer__c (Lookup to Account object for Dealer)
Machine__c (Lookup to parent Machine__c object)
Model__c (Lookup to Model__c object related to Machine__c)
Ownership_Status__c (Picklist with values 'Active' and "InActive")
Stage__c (Picklist)
Transfer_Date__c (Date)


I am trying to write a trigger which will fire after insert of a Machine_Ownership__c object.
I want it to do the following.

For all newly inserted Machine_Ownership objects which have
Ownership_Status__c = 'Active', and
Stage__c = 'Sold'

Update the parent Machine__c object with the following values:

1. Est_Cust_Name__c = Account.name of Customer Account
2. Delivery_Date__c = Transfer_Date__c


I'm not sure what to put in to me test method. Do I have to create "Dummy" objects for each of
Machine__c
Model__c
Customer's Account
Dealer's Account
before creating a new Machine_Ownership__c record which will cause the trigger to execute.

How do I establish the various relationships for the lookup fields?

Here's what I have so far (it fails)

 

The Trigger Class:

trigger setMachineFromMachineOwner on Machine_Ownership__c (after insert) {
	/*
	  If Ownership_Status__c = 'Active' , AND
	     Stage__c = 'Sold'
	  	Get the Machine_c object associated with this new Machine_Ownership__c record.
	  	Set the following fields in Machine__c:
	  	Est_Cust_Name__c	=	Customer__r.Name from Machine_Ownership__c
	  	Install_Date__c		=	Transfer_Date__c from Machine_Ownership__c	  
	*/
	// Get a list of any newly inserted Machine_Ownership records.
	List<Machine_Ownership__c> newOwnership =
		 [SELECT Name, Id, Transfer_Date__c, Customer__r.Name, Machine__r.Name 
          FROM Machine_Ownership__c
          where Ownership_Status__c = 'Active' and Stage__c = 'Sold' and Id in :Trigger.new] ;
    
    // get a list of the associated Machine records
    Map<Id, Machine__c> machinesToUpdate = new Map<Id, Machine__c>();
	for (Machine_Ownership__c mo : newOwnership){
		System.debug('>>>>>>>>> MO:' + mo.name );
		if(!machinesToUpdate.containsKey(mo.Machine__r.Id)){
			Machine__c mach = (Machine__c)mo.getSObject('Machine__r');
			System.debug('>>>>>>>>> Mach: ' + mach.name);
			Account acct = (Account)mo.getSObject('Customer__r');
			System.debug('>>>>>>>>> Cust: ' + acct.name);
			// Set the Machine fields to be changed
			mach.Delivery_Date__c = mo.Transfer_Date__c;
			mach.Est_Cust_Name__c = acct.Name;
			// Add to the map
			machinesToUpdate.put(mo.Machine__r.Id, mach);
		}
    }
    update machinesToUpdate.values();
}

 The Test Class:

@isTest
private class testSetMachineFromMachineOwner {

    static testMethod void testNewMachineOwner() {
        // TO DO: implement unit test
        /*
        	Create a new Machine_Ownership__c record related to:
        	Machine: 2640487 (Id = a07O00000045Mjt) 
        	Model: SYSTEM 150-DM (Id = a06O000000I2WhT)
        	Cust Account: NOKILA HOLDINGS (Id = 001O000000CioDY)
        	DealerAccount : Bertoli Farm Machinery (Id = 001O000000CMkQ1)
        	Set these values:
        	Customer__c = 001O000000CioDY
        	Dealer__c = 001O000000CMkQ1
        	Machine__c = a07O00000045Mjt
        	Model__c = 'a06O000000I2WhT'
        	Stage__c = Sold
        	Ownership_Status__c = Active
        	Transfer_Date__c = Today's Date        	
        */
        Test.startTest(); 
        System.debug('>>>>>>>>> Starting Test');
        Machine_Ownership__c mo = new Machine_Ownership__c(Customer__c ='001O000000CioDY',
Dealer__c = '001O000000CMkQ1', Machine__c = 'a07O00000045Mjt',
Model__c = 'a06O000000I2WhT', Stage__c = 'Sold',Ownership_Status__c = 'Active', Transfer_Date__c = date.today()); System.debug('>>>>>>>>> ' + mo); insert mo; System.debug('>>>>>>>>> Ending Test'); Test.StopTest(); } }

 

I know it's bad practice to use existing Ids when creating test records, but as I've said, I'm unsure how to go about this.

This test results in 55% coverage. What do I need to do to get this to 100%?
How should I use System.assert methods to improve this?
Any other improvements you could suggest would be welcome.

 

When I run this test, I get the following in the Debug Log. What needs to be done to fix this?

Debug Log:

27.0 APEX_CODE,DEBUG;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;VALIDATION,INFO;WORKFLOW,INFO
16:39:09.327 (327939000)|EXECUTION_STARTED
16:39:09.327 (327965000)|CODE_UNIT_STARTED|[EXTERNAL]|01pO0000000DjX6|testSetMachineFromMachineOwner.testNewMachineOwner
16:39:09.328 (328316000)|METHOD_ENTRY|[2]|01pO0000000DjX6|testSetMachineFromMachineOwner.testSetMachineFromMachineOwner()
16:39:09.328 (328330000)|METHOD_EXIT|[2]|testSetMachineFromMachineOwner
16:39:09.328 (328600000)|USER_DEBUG|[23]|DEBUG|>>>>>>>>> Starting Test
16:39:09.329 (329092000)|USER_DEBUG|[26]|DEBUG|>>>>>>>>> Machine_Ownership__c:{Transfer_Date__c=2013-04-11 00:00:00, Machine__c=a07O00000045MjtIAE, Ownership_Status__c=Active, Customer__c=001O000000CioDYIAZ, Model__c=a06O000000I2WhTIAV, Dealer__c=001O000000CMkQ1IAL, Stage__c=Sold}
16:39:09.329 (329140000)|DML_BEGIN|[27]|Op:Insert|Type:Machine_Ownership__c|Rows:1
16:39:09.387 (387126000)|CODE_UNIT_STARTED|[EXTERNAL]|01qO00000008dlL|setMachineFromMachineOwner on Machine_Ownership trigger event AfterInsert for [a08O0000002uD1z]
16:39:09.388 (388028000)|SOQL_EXECUTE_BEGIN|[11]|Aggregations:0|select Name, Id, Transfer_Date__c, Customer__r.Name, Machine__r.Name from Machine_Ownership__c where (Ownership_Status__c = 'Active' and Stage__c = 'Sold' and Id IN :tmpVar1)
16:39:09.400 (400723000)|SOQL_EXECUTE_END|[11]|Rows:1
16:39:09.401 (401371000)|USER_DEBUG|[19]|DEBUG|>>>>>>>>> MO:O - 0213202
16:39:09.401 (401586000)|EXCEPTION_THROWN|[22]|System.NullPointerException: Attempt to de-reference a null object
16:39:09.401 (401733000)|FATAL_ERROR|System.NullPointerException: Attempt to de-reference a null object

Trigger.setMachineFromMachineOwner: line 22, column 1
16:39:09.401 (401753000)|FATAL_ERROR|System.NullPointerException: Attempt to de-reference a null object

Trigger.setMachineFromMachineOwner: line 22, column 1
16:39:10.045 (401791000)|CUMULATIVE_LIMIT_USAGE
16:39:10.045|LIMIT_USAGE_FOR_NS|(default)|
  Number of SOQL queries: 0 out of 100
  Number of query rows: 0 out of 50000
  Number of SOSL queries: 0 out of 20
  Number of DML statements: 1 out of 150
  Number of DML rows: 1 out of 10000
  Number of code statements: 5 out of 200000
  Maximum heap size: 0 out of 6000000
  Number of callouts: 0 out of 10
  Number of Email Invocations: 0 out of 10
  Number of fields describes: 0 out of 100
  Number of record type describes: 0 out of 100
  Number of child relationships describes: 0 out of 100
  Number of picklist describes: 0 out of 100
  Number of future calls: 0 out of 10

16:39:10.045|TESTING_LIMITS
16:39:10.045|LIMIT_USAGE_FOR_NS|(default)|
  Number of SOQL queries: 1 out of 100
  Number of query rows: 1 out of 50000
  Number of SOSL queries: 0 out of 20
  Number of DML statements: 0 out of 150
  Number of DML rows: 0 out of 10000
  Number of code statements: 5 out of 200000
  Maximum heap size: 0 out of 6000000
  Number of callouts: 0 out of 10
  Number of Email Invocations: 0 out of 10
  Number of fields describes: 0 out of 100
  Number of record type describes: 0 out of 100
  Number of child relationships describes: 0 out of 100
  Number of picklist describes: 0 out of 100
  Number of future calls: 0 out of 10

16:39:10.045|CUMULATIVE_LIMIT_USAGE_END

16:39:09.401 (401851000)|CODE_UNIT_FINISHED|setMachineFromMachineOwner on Machine_Ownership trigger event AfterInsert for [a08O0000002uD1z]
16:39:09.404 (404974000)|DML_END|[27]
16:39:09.405 (405059000)|EXCEPTION_THROWN|[27]|System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, setMachineFromMachineOwner: execution of AfterInsert

caused by: System.NullPointerException: Attempt to de-reference a null object

Trigger.setMachineFromMachineOwner: line 22, column 1: []
16:39:09.406 (406132000)|FATAL_ERROR|System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, setMachineFromMachineOwner: execution of AfterInsert

caused by: System.NullPointerException: Attempt to de-reference a null object

Trigger.setMachineFromMachineOwner: line 22, column 1: []

Class.testSetMachineFromMachineOwner.testNewMachineOwner: line 27, column 1
16:39:09.406 (406150000)|FATAL_ERROR|System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, setMachineFromMachineOwner: execution of AfterInsert

caused by: System.NullPointerException: Attempt to de-reference a null object

Trigger.setMachineFromMachineOwner: line 22, column 1: []

Class.testSetMachineFromMachineOwner.testNewMachineOwner: line 27, column 1
16:39:10.050 (406166000)|CUMULATIVE_LIMIT_USAGE
16:39:10.050|LIMIT_USAGE_FOR_NS|(default)|
  Number of SOQL queries: 0 out of 100
  Number of query rows: 0 out of 50000
  Number of SOSL queries: 0 out of 20
  Number of DML statements: 1 out of 150
  Number of DML rows: 1 out of 10000
  Number of code statements: 5 out of 200000
  Maximum heap size: 0 out of 6000000
  Number of callouts: 0 out of 10
  Number of Email Invocations: 0 out of 10
  Number of fields describes: 0 out of 100
  Number of record type describes: 0 out of 100
  Number of child relationships describes: 0 out of 100
  Number of picklist describes: 0 out of 100
  Number of future calls: 0 out of 10

16:39:10.050|TESTING_LIMITS
16:39:10.050|CUMULATIVE_LIMIT_USAGE_END

16:39:09.406 (406190000)|CODE_UNIT_FINISHED|testSetMachineFromMachineOwner.testNewMachineOwner
16:39:09.406 (406197000)|EXECUTION_FINISHED

 Many thanks in advance for your help.

hitesh90hitesh90

Hi,

 

here is your trigger calls recursively because of that error occurs. you have to use static variable to handle this issue as below.

 

Apex trigger:

 

trigger setMachineFromMachineOwner on Machine_Ownership__c (after insert) {
	if(clsStaticVar.blnIsMachineOwnershipInsert == false) {
        return;
    }
	clsStaticVar.blnIsMachineOwnershipInsert = false;
	/*
	  If Ownership_Status__c = 'Active' , AND
	     Stage__c = 'Sold'
	  	Get the Machine_c object associated with this new Machine_Ownership__c record.
	  	Set the following fields in Machine__c:
	  	Est_Cust_Name__c	=	Customer__r.Name from Machine_Ownership__c
	  	Install_Date__c		=	Transfer_Date__c from Machine_Ownership__c	  
	*/
	// Get a list of any newly inserted Machine_Ownership records.
	List<Machine_Ownership__c> newOwnership =
		 [SELECT Name, Id, Transfer_Date__c, Customer__r.Name, Machine__r.Name 
          FROM Machine_Ownership__c
          where Ownership_Status__c = 'Active' and Stage__c = 'Sold' and Id in :Trigger.new] ;
    if(clsStaticVar.blnIsMachineOwnershipInsert == true){
		// get a list of the associated Machine records
		Map<Id, Machine__c> machinesToUpdate = new Map<Id, Machine__c>();
		for (Machine_Ownership__c mo : newOwnership){
			System.debug('>>>>>>>>> MO:' + mo.name );
			if(!machinesToUpdate.containsKey(mo.Machine__r.Id)){
				Machine__c mach = (Machine__c)mo.getSObject('Machine__r');
				System.debug('>>>>>>>>> Mach: ' + mach.name);
				Account acct = (Account)mo.getSObject('Customer__r');
				System.debug('>>>>>>>>> Cust: ' + acct.name);
				// Set the Machine fields to be changed
				mach.Delivery_Date__c = mo.Transfer_Date__c;
				mach.Est_Cust_Name__c = acct.Name;
				// Add to the map
				machinesToUpdate.put(mo.Machine__r.Id, mach);
			}
		}
		update machinesToUpdate.values();
	}
}

 

Apex Class:

 

Public Class clsStaticVar {
    Public Static Boolean blnIsMachineOwnershipInsert = true;
}

 

 

Important :

Hit Kudos if this provides you with useful information and if this is what you where looking for then please mark it as a solution for other benefits.

 

 

Thanks,

Hitesh Patel

RonVRonV

I did some more reading, and now seem to have the trigger working. However, I'd welcome any suggestions as to how it may be improved, particularly with regard any situations where multiple Machine_Ownership__c records might be created at once. I think I have it covered, but would welcome advice. the code now looks like this:

 

Trigger:

trigger setMachineFromMachineOwner on Machine_Ownership__c (after insert) {
       /*
         If Ownership_Status__c = 'Active' , AND
            Stage__c = 'Sold'
              Get the Machine_c object associated with this new Machine_Ownership__c record.
              Set the following fields in Machine__c:
                     Est_Cust_Name__c = Customer__r.Name from Machine_Ownership__c
                     Delivery_Date__c = Transfer_Date__c from Machine_Ownership__c   
       */
       // Get a list of any newly inserted Machine_Ownership records.
       List<Machine_Ownership__c> newOwnership =
              [SELECT Name, Id, Transfer_Date__c, Customer__r.Name, Machine__r.Name 
          FROM Machine_Ownership__c
          where Ownership_Status__c = 'Active' and Stage__c = 'Sold' and Id in :Trigger.new] ;
    
    // get a list of the associated Machine records
    Map<Id, Machine__c> machinesToUpdate = new Map<Id, Machine__c>();
       for (Machine_Ownership__c mo : newOwnership){
              System.debug('>>>>>>>>> MO:' + mo.name );
              if(!machinesToUpdate.containsKey(mo.Machine__r.Id)){
                     Machine__c mach = (Machine__c)mo.getSObject('Machine__r');
                     System.debug('>>>>>>>>> Mach: ' + mach.name);
                     Account acct = (Account)mo.getSObject('Customer__r');
                     System.debug('>>>>>>>>> Cust: ' + acct.name);
                     // Set the Machine fields to be changed
                     mach.Delivery_Date__c = mo.Transfer_Date__c;
                     mach.Est_Cust_Name__c = acct.Name.substring(0,15);
                     // Add to the map
                     machinesToUpdate.put(mo.Machine__r.Id, mach);
              }
    }
    update machinesToUpdate.values();
}

 And the Test Class (100% Coverage)

@isTest
private class testSetMachineFromMachineOwner {

    static testMethod void testNewMachineOwner() {
       // Create test records
        Account cacc = new Account(name = 'Trigger Test Customer Account');
        insert cacc;
        Account dacc = new Account(name= 'Trigger Test Dealer Account');
        insert dacc;
        Model__c mdl = new Model__c(item__c='Test Model',item_Description__c='Test Model');
        insert mdl;
        Machine__c mach = new Machine__c(name='testMach', lotnumber__c = 'testMach', Model__c = mdl.Id, Location__c = dacc.Id);
        insert mach;
        
        Test.startTest(); 
        System.debug('>>>>>>>>> Starting Test');
        Machine_Ownership__c mo = new Machine_Ownership__c(Customer__c = cacc.Id,Dealer__c = dacc.Id,
              Machine__c = mach.Id,Model__c = mdl.Id, Stage__c = 'Sold',Ownership_Status__c = 'Active',Transfer_Date__c = date.today());
        System.debug('>>>>>>>>> ' + mo);
              insert mo;
                     System.Debug('>>>>>>>>>>>  ASSERT...ASSERT');
                     Machine__c a = [select Est_Cust_Name__c, Delivery_Date__c from Machine__c where Id = :mach.Id];
                     System.assertEquals(a.Est_Cust_Name__c, cacc.Name.substring(0,15),'Est_Cust_Name is not equal');
                     System.assertEquals(a.Delivery_Date__c, mo.Transfer_Date__c, 'Transfer Date is not equal');
        System.debug('>>>>>>>>> Ending Test');
        Test.StopTest();
              
    }
}

 Thanks

jisn mosejisn mose
Hey, Can you please share the complete program of this script? I want to use it for my small juicer article (https://bestjuicer2021.com/best-small-juicer-2021/) that hosted on WordPress.