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
megan.burchmegan.burch 

Need Help with Apex Test Class

I wrote this simple trigger which is working fine, but the test class I wrote isn't covering any code. The trigger fills a custom text field (market) on the account page to match another custom field on the account page (geojunction). The market field also could get written into by an ETL load so thats why it had to be a text field. Any input would be great. Thanks

 

Trigger

	trigger MarketoffGeoJunctionTrigger on Account (before Insert, before Update) {

     if (Trigger.isInsert) {
        for(Account a : Trigger.new){
            List<geojunction__c> GeoJunction = [select name,id from GeoJunction__c where id=: a.geojunction__c];
            for (GeoJunction__c g : GeoJunction) {
              if(a.geojunction__c !=null){
                     a.market__c = g.name;
                }
            }
        } 
    }
     if (Trigger.isUpdate) {
     for(Account a : Trigger.new){
     List<geojunction__c> GeoJunction = [select name,id from GeoJunction__c where id=: a.geojunction__c];
            for (GeoJunction__c g : GeoJunction) {
                 if(a.geojunction__c !=null){
                    a.market__c=g.name;
                }
            }
        }
    }
}

 Class

@istest public class MarketoffGeoJunctionTriggerTest{
  static testMethod void MarketoffGeoJunctionTriggerTest(){
        
        Geojunction__c g1 = new Geojunction__c();

        g1.name = 'test';
        
        insert g1;

        g1 = [Select Id, name from geojunction__c where ID = :g1.ID];
        
          Account a1 = new Account();
       
         a1.Name = 'Test Account';
         a1.geojunction__c = g1.id;
         a1.market__c = g1.name;
                         
      
        insert a1;

    system.assertequals(g1.name,a1.geojunction__c);

         a1.Name = 'Test Account';
         a1.geojunction__c = 'test';
         a1.market__c = g1.name;
      
      
          update a1;
      
          system.assertequals(g1.name,a1.geojunction__c);
   }
}

 

Sean TanSean Tan

Couple of things...

 

  1. Do you really need a trigger for what you're doing? If the geojunction__c is a lookup field could you not use a formula field to display the geojunction name?
  2. You're trigger is not bulk safe and is repetitive (the logic is exactly the same for insert vs update of the account).
  3. Your test class is failing because you're comparing the account geojunction id to the geojunction name which doesn't work.

Below is the fixed trigger / test class, but see point #1 about the formula field approach:

 

Trigger:

trigger MarketoffGeoJunctionTrigger on Account (before Insert, before Update) {
	
	Map<Id, GeoJunction__c> junctionMap = new Map<Id, GeoJunction__c>{};
	
	for (Account a : Trigger.new)
	{
		if (a.geojunction__c != null)
		{
			junctionMap.put(a.geojunction__c, null);
		}
	}
	
	if (!junctionMap.isEmpty())
	{
		junctionMap.putAll([[select name,id from GeoJunction__c where id=: junctionMap.keySet()]); 
		
		for (Account a : Trigger.new)
		{
			if (a.geojunction__c != null)
			{
				GeoJunction g = junctionMap.get(a.geojunction__c);
				a.market__c = g.name;				
			}
		}
	}	
}

 Test class:

@istest 
public class MarketoffGeoJunctionTriggerTest{
    static testMethod void MarketoffGeoJunctionTriggerTest(){
        
        Geojunction__c g1 = new Geojunction__c();        
        g1.name = 'test';        
        insert g1;
        
        Account a1 = new Account();        
        a1.Name = 'Test Account';
        a1.geojunction__c = g1.id;                    
        insert a1;        
        
        a1 = [ select Id, market__c from Account where Id = :a1.Id];        
        system.assertequals(g1.name,a1.market__c);
        
        Geojunction__c g2 = new Geojunction__c();
        g2.name = 'test2';
        insert g2;
                
        a1.geojunction__c = g2.Id;        
        update a1;
        
        a1 = [ select Id, market__c from Account where Id = :a1.Id];        
        system.assertequals(g2.name,a1.market__c);
    }
}

 

megan.burchmegan.burch

Thank you very much! I really appreciate it

 

I didn't use a formula field becuase I wasn't sure if the ETL could write into the field if it was a formula.

 

I used your test and class and I'm still getting no coverage.

Sean TanSean Tan

Is the test class failing, or is it just not covering any lines of code within the trigger?

megan.burchmegan.burch

Both

Sean TanSean Tan

What error message are you getting for the failure?

megan.burchmegan.burch

It's running the test method just isn't passing and the coverage data is at 0%.

 

When I run the test and go to the debug logs i'm getting this messag e

 

Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [Geo_Codes__c, Market_Assignments__c]: [Geo_Codes__c, Market_Assignments__c]

Sean TanSean Tan

I don't know enough of the data model to help too much with this, but essentially when inserting the Geojunction you also have to set the geo_codes__c and market_assignments__c values.

 

Like so:

 

@istest 
public class MarketoffGeoJunctionTriggerTest{
    static testMethod void MarketoffGeoJunctionTriggerTest(){
        
        Geojunction__c g1 = new Geojunction__c();    
        g1.Geo_Codes__c = '';//Insert the geo_codes... if this is a lookup you have to insert that record
        g1.Market_Assignments__c = '';//Same as the geo_codes
        g1.name = 'test';        
        insert g1;
        
        Account a1 = new Account();        
        a1.Name = 'Test Account';
        a1.geojunction__c = g1.id;                    
        insert a1;        
        
        a1 = [ select Id, market__c from Account where Id = :a1.Id];        
        system.assertequals(g1.name,a1.market__c);
        
        Geojunction__c g2 = new Geojunction__c();
        g2.name = 'test2';
        g2.Geo_Codes__c = '';//Insert the geo_codes... if this is a lookup you have to insert that record
        g2.Market_Assignments__c = '';//Same as the geo_codes
        insert g2;
                
        a1.geojunction__c = g2.Id;        
        update a1;
        
        a1 = [ select Id, market__c from Account where Id = :a1.Id];        
        system.assertequals(g2.name,a1.market__c);
    }
}

 

megan.burchmegan.burch

Thanks. Geojunction is a junction object with geocodes and market assignement. I'll try inserting those as well.

megan.burchmegan.burch

I did this backwards. The market field is populated from and ETL load and I want the geojunction field one the account page to match the market only if the geojunction exists in the geojunction object. Any suggestions on that without a validation rule?

Sean TanSean Tan

So if I'm understanding you correctly, you have the following objects in Salesforce:

 

Geo_Junction__c

Market_Assignments__c

 

The Account has the following fields:

Market__c - Flat field with just a text string

Geo_Junction__c - Lookup the Geo_Junction__c table

 

If this gets populated you want to find the Geo_Junction__c record with the associated Market Assignment, than assign that to the Account's Geo_Junction__c reference.

 

Is this correct?

 

If so is it possible for multiple Geo_Junction__c records to exist for the same Market_Assignment__c? (I assume yes otherwise what's the point of the junction table). In the case there are multiple Geo Junction records for that Market Assignment, which Geo Junction should be used?

megan.burchmegan.burch

This part is correct

 

Geo_Junction__c

Market_Assignments__c

 

The Account has the following fields:

Market__c - Flat field with just a text string

Geo_Junction__c - Lookup the Geo_Junction__c table

 

Once the geojunction__c lookup field is populated on the account page then there are 3 other formula fields that use that information to populate.

 

When the market field is written into the account I want that value to populate the geojunction lookup field on the account if that value exists in the geojunction object. The market that is being written in will either match exactly to a geojunction or have no match, it will not have multiple matches.

 

Thank you!

Sean TanSean Tan

Something like this should get you on the right direction...

 

You'll most likely need to adjust the query to match appropriately based off what the account market value matches against in the geojunction table...

trigger MarketoffGeoJunctionTrigger on Account (before Insert, before Update) {
    
    Map<String, GeoJunction__c> junctionMap = new Map<String, GeoJunction__c>{};
    
    for (Account a : Trigger.new)
    {
        if (a.Market__c != null &&
        (Trigger.isInsert || (Trigger.isUpdate && Trigger.oldMap.get(a.Id) != a.Market__c)))
        {            
            //Ignore casing in the map
            junctionMap.put(a.Market__c.toLowerCase(), null);            
        }
    }
    
    if (!junctionMap.isEmpty())
    {    
        //Customize this as needed
        //Not sure what field you're matching against... but adjust the where clause
        //and whatever the market__c field matches to
        for (GeoJunction__c item : [ select Id, Name from GeoJunction__c where Name IN :junctionMap.keySet()] )
        {
            junctionMap.put(item.Name.toLowerCase(), item);
        }
                        
        for (Account a : Trigger.new)
        {
            if (a.market__c != null)
            {
                GeoJunction g = junctionMap.get(a.market__c.toLowerCase());
                
                if (g != null)
                {
                    a.geojunction__c = g.Id;                
                }
                else
                {
                    //In case no match... clear out the geo junction??
                    //If this is not needed remove this code
                    a.geojunction__c = null;
                }
            }
        }
    }    
}

 

megan.burchmegan.burch

Thank you so much.

 

I kept getting an error on line 29

 

 GeoJunction g = junctionMap.get(a.market__c.toLowerCase());

 

and changed the first part to GeoJunciton__c g=

 

but now I keep getting this error on line 8

  Error: Compile Error: Comparison arguments must be compatible types: SOBJECT:Account, String at line 8 column 51

 

(Trigger.isInsert || (Trigger.isUpdate && Trigger.oldMap.get(a.Id) != a.Market__c)))

megan.burchmegan.burch

I commented out the lines with the error and it woks great! Thanks! The only issue is when market is left blank or deleted and the account is saved I get this error

 

Apex trigger GeoJunctionTrigger caused an unexpected exception, contact your administrator: GeoJunctionTrigger: execution of BeforeUpdate caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.GeoJunctionTrigger: line 11, column 1

Sean TanSean Tan

Instead of commenting out this should fix the issue with that error...

 

trigger MarketoffGeoJunctionTrigger on Account (before Insert, before Update) {
    
    Map<String, GeoJunction__c> junctionMap = new Map<String, GeoJunction__c>{};
    
    for (Account a : Trigger.new)
    {
        if (a.Market__c != null &&
        (Trigger.isInsert || (Trigger.isUpdate && Trigger.oldMap.get(a.Id).Market__c != a.Market__c)))
        {            
            //Ignore casing in the map
            junctionMap.put(a.Market__c.toLowerCase(), null);            
        }
    }
    
    if (!junctionMap.isEmpty())
    {    
        //Customize this as needed
        //Not sure what field you're matching against... but adjust the where clause
        //and whatever the market__c field matches to
        for (GeoJunction__c item : [ select Id, Name from GeoJunction__c where Name IN :junctionMap.keySet()] )
        {
            junctionMap.put(item.Name.toLowerCase(), item);
        }
                        
        for (Account a : Trigger.new)
        {
            if (a.market__c != null)
            {
                GeoJunction g = junctionMap.get(a.market__c.toLowerCase());
                
                if (g != null)
                {
                    a.geojunction__c = g.Id;                
                }
                else
                {
                    //In case no match... clear out the geo junction??
                    //If this is not needed remove this code
                    a.geojunction__c = null;
                }
            }
        }
    }    
}

 

megan.burchmegan.burch

Awesome!! Thank you so much it works great

megan.burchmegan.burch

Sorry, I had one more question you may be able to help me with.

 

When the geojunciton field on the account is popoulated it fills in a field called market assignement on the account from a custom object called market assignement which also contains a field called market manager.

 

When the account owner = X X I want to take the market manager from the market assignement object and use it as the owner. Can I build that into the trigger I already wrote or should I write another one?

 

Thanks!

megan.burchmegan.burch

This isn't working for an update. If a record already exists with the market filled in and no geojunction when I edit and save the geojunction is still not being filled in. Any suggesitons?