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
huskerwendyhuskerwendy 

Test class isn't making Trigger Execute

I have a trigger on assets that inserts records into a custom object dependent on the product family and if the value of some custom fields changes. The trigger works fine when I edit records in the user interface in Salesforce. However, I can't make the trigger fire from my test class. I'm not sure why. The "RMR__c" field is updated via a workflow rule on the asset when the "Num_Users_Devices__c" or "RMR_Per_Unit__c". The test class will never go into the "if (trigger.IsUpdate && ((a.Product2.Family == "Cloud IT'......for loop in the trigger.  I'm using a data factory to create the test data and passing in the Product Family but it seems as though the product family is empty in my test class. How can I see what the product family is for the asset?

Here's the Data Factory method to create the product.

public static void createProductWithFamily(String productName, String productFamily){
       // First, set up test price book entries. // Insert a test product.
    	Product2 prod = new Product2(Name = productName, Family = productFamily);
        insert prod;
          system.debug('**** in createProductWithFamily ' + prod);
        // Get standard price book ID.  // This is available irrespective of the state of SeeAllData.   
        Id pricebookId = Test.getStandardPricebookId();
 
        // Insert a price book entry for the standard price book. Standard price book entries require the standard price book ID we got earlier.
        PricebookEntry standardPrice = new PricebookEntry(Pricebook2Id = pricebookId, Product2Id = prod.Id, UnitPrice = 500, IsActive = true);
        insert standardPrice;
         // Create a custom price book
        Pricebook2 customPB = new Pricebook2(Name='Sales', isActive=true);
        insert customPB;
        // 2. Insert a price book entry with a custom price.
        PricebookEntry customPrice = new PricebookEntry(Pricebook2Id = customPB.Id, Product2Id = prod.Id,UnitPrice = 500, IsActive = true);
         insert customPrice; 
    }

Here's the trigger

trigger trgAsset on Asset (after insert, after update, after delete) {
	if (trigger.isInsert || trigger.isUpdate){
		/*If the asset is a Cloud it Product and the number of users changes, the trigger will insert a record into the Cloud_IT_Armor_Gain_Loss__c object with the armor gain or loss*/
		set<id> assetIds = new Set<id>(); // create a set of all asset ids to get the Product family
	    for (Asset a : Trigger.new){ 
	    	assetIds.add(a.Id);
	    }
        // create list of records to insert into Cloud_IT_Armor_Gain_lost object
       list<User_Device_ARMOR_Gain_Lost__c> insertRecords = new list<User_Device_ARMOR_Gain_Lost__c>();
        // loop through assets and get Id and product family
     	set<Asset> assts = new set<Asset>([Select Id, Product2.Family from Asset Where Id in :assetIds]);
       	system.debug('****** in trigger assts before for loop ' + assts);
 		//if trigger is update and product family = CloudIT or Floor 99 Legacy and old Armor is not equal to the new Armor and Old Num Users <> New Num Users
      	for (Asset a: assts){
          if (trigger.isUpdate && 
			((a.Product2.Family == 'Cloud IT' || a.product2.Family == 'Floor 99 Legacy') && (Trigger.oldMap.get(a.Id).RMR__c <> Trigger.newMap.get(a.Id).RMR__c)
 			&& ((Trigger.oldMap.get(a.Id).Num_Users_Devices__c <> Trigger.newMap.get(a.Id).Num_Users_Devices__c) || (Trigger.oldMap.get(a.Id).RMR_Per_Unit__c <> Trigger.newMap.get(a.Id).RMR_Per_Unit__c)))){
                    system.debug('**** in trigger asset in for loop is ' + a);
              Date ArmorDate = Date.Today();
              Id AsstID = a.Id;
              decimal PrevArmor =  Trigger.oldMap.get(a.Id).RMR__c;            
              decimal NewArmor = Trigger.newMap.get(a.Id).RMR__c;
              decimal Gain = 0;
              decimal Loss = 0;
              if (Trigger.newMap.get(a.Id).RMR__c > Trigger.oldMap.get(a.Id).RMR__c){
              	Gain = Trigger.newMap.get(a.Id).RMR__c -  Trigger.oldMap.get(a.Id).RMR__c;
              }else if (Trigger.newMap.get(a.Id).RMR__c < Trigger.oldMap.get(a.Id).RMR__c){
              	Loss = Trigger.oldMap.get(a.Id).RMR__c - Trigger.newMap.get(a.Id).RMR__c ;
              }                     
            User_Device_ARMOR_Gain_Lost__c c = new User_Device_ARMOR_Gain_Lost__c(
              	Asset__c = a.Id,
              	Armor_Date__c = ArmorDate,  
				Previous_Armor__c = PrevArmor,
				New_Armor__c = NewArmor,
              	Armor_Gain__c = Gain,
              	Armor_Lost__c = Loss);   
              insertRecords.add(c);
          }           
      	}
        
        system.debug('**** in trigger insertRecords is ' + insertRecords);
        // if the Num users or armor has changed insert the records
        if (insertRecords.size()>0){
           insert insertRecords; 
       } 	
    }		   
}

Here's the Test Class
/*test for the user/device ARMOR Gains/losses on assets */
@isTest(SeeAllData=false)
private class TestTrgAssetArmorGainsLoss {
    static testMethod void myUnitTest() {
            // create user to run the test a
            User u =  TestDataFactory.createTestRunAsUser('System Administrator', 'System Admin');  
            
            System.runAs(u) {  
            	// Switch to the runtime 
            	Test.StartTest();
             		TestDataFactory.createProductWithFamily('Base Cloud', 'Cloud IT');
               		list<Account> printAccts = TestDataFactory.createTestAccounts(2, 'Other', 'Client');    		
                 	list<Asset> asstCIT = TestDataFactory.createCloudITAssets(printAccts, date.today(), 'Base Cloud', 'Purchased', 10.00, 375, 10);
                	performUpdateAssetNumUsers(asstCIT);
                	checkUserArmorGainLost(asstCIT);
                Test.StopTest();   
             }
        }
	
    public static void performUpdateAssetNumUsers(list<Asset> asst){
        date now = date.today();
        system.debug('**** in performUpdateAssetNumUsers asset list is ' + asst);
        //update the number of users on the asset
        list<Asset>updateAsset = new list<Asset>();
        
		for (Asset ass : asst){
            system.debug('*** in performUpdateAssetNumUsers for loop ass is ' + ass);
            Asset ua = new Asset(
                id = ass.id,
                Num_Users_Devices__c = 12,
                RMR_Per_Unit__c = 10.00);
			updateAsset.add(ua);
       }   
        system.debug('**** in performUpdateAssetNumUsers after update' + updateAsset);
		update updateAsset;
    }
    
    public static void checkUserArmorGainLost(list<Asset> asst){
        //check results of assets to be sure the user/Device ARMOR Gains/Losses records was created.
		list <Asset> assts = [Select Id, RMR__c, Armor_date__c, Num_Users_Devices__c, Product2.Family from Asset Where Id =: asst];
   //     list<Product2> prod = [Select Id, Name, Family from Product2 where Id =: assts.Product2.Id];
   //     system.debug('**** in checkuserArmorGainLost prod is ' + prod);
         
        system.debug('***** assts after update is' + assts);
        list<Id> checkList = new list<id>();
        for (Asset a : assts){
            system.debug('**** asset a in for loop is ' + a);
            checkList.add(a.id);
        }
        set <User_Device_ARMOR_Gain_Lost__c> gainLost = new set<User_Device_ARMOR_Gain_Lost__c>([Select Id, Asset__c, Armor_date__c, Armor_Gain__c, Armor_Lost__c from User_Device_ARMOR_Gain_Lost__c /*Where Asset__c in: checkList */]);
        system.debug('***** gainLost is ' + gainLost);
	//	for (User_Device_ARMOR_Gain_Lost__c g : gainLost){
	//		System.assertEquals(now, g.Armor_date__c);   
	//	}  
        
    }   
}

kaustav goswamikaustav goswami
I think the issue is you have not updated the field RMR__c on the asset records. You will have to perform an update on the value of that field if you want to satisfy the entire logic in the if condition.

Thanks,
Kaustav
huskerwendyhuskerwendy
Thanks, Kaustav but I don't think that's the problem. I commented out the check for the product family in the if statement and it works. it's that the product family isn't there for the asset in the test class but I don't know why.

This is the line that I commented out the check for the product family.

if (trigger.isUpdate &&
   (/*(a.Product2.Family == 'Cloud IT' || a.product2.Family == 'Floor 99 Legacy') &&*/ (Trigger.oldMap.get(a.Id).RMR__c <> Trigger.newMap.get(a.Id).RMR__c)
    && ((Trigger.oldMap.get(a.Id).Num_Users_Devices__c <> Trigger.newMap.get(a.Id).Num_Users_Devices__c) || (Trigger.oldMap.get(a.Id).RMR_Per_Unit__c <> Trigger.newMap.get(a.Id).RMR_Per_Unit__c)))){

In the test class, how can the asset see the product family for the product?


kaustav goswamikaustav goswami
In line 13 where you have called the data factory method to create the assets you have passed 'Base Cloud' as the family where as the if condition in your trigger is checking for Cloud IT or Legacr Floor 99. Can you please change that and see if it works.
list<Asset> asstCIT = TestDataFactory.createCloudITAssets(printAccts, date.today(), 'Base Cloud', 'Purchased', 10.00, 375, 10);
Thanks,
Kaustav
huskerwendyhuskerwendy
Hi Kaustav,

This is making me crazy and I really appreciate your help. In that method, I'm passing the product name to the method. I'm creating the product on line 11 in the test class. When I'm inside the method for creating the assets, it appears as though the product family is correct when I look at the debug statements.

 Here's the method for creating the asset. 
public static list<Asset> createCloudITAssets(list<Account> accounts, Date purchaseDate, String productName, String prodStatus, decimal RMRPerUnit, decimal prce, integer NumUsers ){
        list<Asset> assts = new list<Asset>();
        Product2 prod = [select Id, Name, Family from Product2 where Name =: productName];
				
        system.debug('**** in data factory createCloudITAssets product is ' + prod);
        // create an asset for each account
        for (Account acct : accounts ){
            Asset a = new Asset(
                Product2 = prod,
                Name = productName,
                AccountID = acct.Id,
                Status = prodStatus,
                PurchaseDate = purchaseDate,
                Num_Users_Devices__c = NumUsers,
                RMR_Per_Unit__c = RMRPerUnit,
                Price = prce);
            assts.add(a);    
            system.debug('**** in createCloudITAssets product2 is ' + a.Product2);
        }
        insert assts;   
        list <Asset> assetsCIT = [select Id, Name, AccountId, Armor_Date__c, Num_Users_Devices__c, RMR_Per_Unit__c, RMR__c, product2.Family  FROM Asset where Id in: assts]; 
        system.debug('**** in createCloudITAssets assetsCIT is ' + assetsCIT);
        
        return assts;
    }

Both debug statements in this method show the product family as Cloud IT

|USER_DEBUG|[200]|DEBUG|**** in data factory createCloudITAssets product is Product2:{Name=Base Cloud, Family=Cloud IT, Id=01tm0000000cn3aAAA}

USER_DEBUG|[213]|DEBUG|**** in createCloudITAssets product2 is Product2:{Name=Base Cloud, Family=Cloud IT, Id=01tm0000000cn3aAAA}

However the debug statement in the trigger on line 12 isn't returning the Produc2.Family. It's only returning the Asset ID which makes me think that it doesn't know what the product family is or I'm accessing it incorrectly.

Here's the statement:
set<Asset> assts = new set<Asset>([Select Id, Product2.Family from Asset Where Id in :assetIds]);
system.debug('****** in trigger assts before for loop ' + assts);

USER_DEBUG|[22]|DEBUG|****** in trigger assts before for loop {Asset:{Id=02im00000008yPCAAY}, Asset:{Id=02im00000008yPDAAY}}


kaustav goswamikaustav goswami
Can you please change lines 26 to 33 of your test class to the following and then give it a try. Also if possible can you please post what the debug id showing in lne 34 of your test class.

for (Asset ass : asst){
	system.debug('*** in performUpdateAssetNumUsers for loop ass is ' + ass);
	ass.Num_Users_Devices__c = 12;
	ass.RMR_Per_Unit__c = 10.00;
	updateAsset.add(ass);
}
Thanks,
Kaustav

huskerwendyhuskerwendy
Hi Kaustav,

Thanks for the help on this. Changing the for loop didn't help my problem with the asset not being able to see the Product Family on the product. For now, I changed my trigger to only check if the RMR_Per_Unit__c or Num_Users_Devices__c values change since those fields don't apply to any other products except for products in those two prouct families anyway. 

Wendy