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
Melissa HallMelissa Hall 

Help with test code please

I'm very new to development, and this is the first Apex Class I've built not using the training courses as guidelines.  My Apex Class and Trigger seem to be working fine, but I'm only getting 50% coverage on my test code.  I'm studied dozens of test code over the last two weeks, and tried oh so many attempts to get this to work, but just don't have the knowledge yet to troubleshoot.

In a nutshell, when an Opportunity is 30 days prior to CloseDate, I need to check a box on the Opp that will trigger a Process Builder process that my admin can maintain.  So simple, yet for some reason so complicated.

Can someone point me in the right direction?  Thanks!

Apex Class
public class OFACMCOQuote {
	
	//create list of Opps
	public static void OFACTask(List<Opportunity> oppList){
		System.Debug('OFACTask: Entering');
			
		oppList = [SELECT Id, Name, isMCOOFACQuoteTriggered__c
	  			   FROM Opportunity 
	  			   WHERE (Type = 'Renewal' OR Type = 'Guaranteed Renewal') 
	  			     AND isClosed = False
	  			     AND Market_Segment__c = 'Managed Care Organization'
	  			     AND CloseDateTrigger_30__c <= TODAY
	  			     AND isMCOOFACQuoteTriggered__c = False]; {
	  				  	  
	 		//field update to trigger process
	 		for(Opportunity opp : oppList) {
	  			System.debug('Name: ' + opp.Name);
	  			if (!oppList.isEmpty()){
					opp.isMCOOFACQuoteTriggered__c = True;	  				
	  			}
	  		}
	 		update oppList;
	  	}	
	}  					 
}
Apex Trigger
trigger OFACMCOTriggers on Opportunity (after insert, after update) {
	OFACMCOQuote.OFACTask(Trigger.new);
	OFACMCOBinder.OFACTask(Trigger.new);
}
Test Class:
@isTest
private class OFACMCOQuote_Test {

	//Verify that OFAC task and notification are triggered
    static testMethod void OFACTask_Test() {
        
		//Load test Profile
    	Map<String, Profile> profiles = new Map<String, Profile>();
        for(Profile p : [select id, name from profile where name IN ('System Administrator')]){
            profiles.put(p.Name, p);
        }
        
        //Load test User
        User u1 = new User(alias = 'test01', email='test01@testorg.com',
                        emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US',
                        localesidkey='en_US', profileid = profiles.get('System Administrator').Id,
                        timezonesidkey='America/Los_Angeles', username='test01@testorg.com', CommunityNickname = 'test01');
    	insert new List<User>{u1};
        
        //Load test Account 
      	Account acc1 = new Account(Name='Test01', Managing_Director_lu__c = u1.Id);
        insert new List<Account>{acc1};
    
        //Load test Opportunity 
      	Opportunity opp1 = new Opportunity(AccountId = acc1.Id, Name = 'Test Opp 1', StageName = 'Qualified', Submission_Entry__c = FALSE, 
      										Managing_Director_lu__c = u1.Id, Market_Segment__c = 'Managed Care Organization', 
      										Type = 'Renewal', CloseDate = date.Today()/*, isMCOOFACQuoteTriggered__c = TRUE*/);
      	//Opportunity opp2 = new Opportunity(AccountId = acc1.Id, Name = 'Test Opp 2', StageName = 'Qualified', Submission_Entry__c = FALSE, 
      		//								Managing_Director_lu__c = u1.Id, CloseDate = Date.today(), isMCOOFACQuoteTriggered__c = FALSE);
      	insert new List<Opportunity>{opp1};
      	
      	opp1.CloseDate = opp1.MCOOFACDateHelper__c;
      	update new List<Opportunity>{opp1};
      	        
        Map<Id, Opportunity> opps2Check = new Map<Id, Opportunity>([SELECT Id, CloseDate, isMCOOFACQuoteTriggered__c
        															FROM Opportunity WHERE Id IN :new List<Opportunity>{opp1}]);
        System.assert(opps2Check.get(opp1.Id).isMCOOFACQuoteTriggered__c);
        System.assertEquals(opp1.isMCOOFACQuoteTriggered__c,opps2Check.get(opp1.Id).isMCOOFACQuoteTriggered__c);
        //System.assertNotEquals(opp2.isMCOOFACQuoteTriggered__c,opps2Check.get(opp2.Id).isMCOOFACQuoteTriggered__c);       
    }
}
Amit Chaudhary 8Amit Chaudhary 8
Please update your test class like below
@isTest
private class OFACMCOQuote_Test 
{
    static testMethod void OFACTask_Test() 
	{
        
    	Map<String, Profile> profiles = new Map<String, Profile>();
        for(Profile p : [select id, name from profile where name IN ('System Administrator')])
		{
            profiles.put(p.Name, p);
        }
        
        User u1 = new User(alias = 'test01', email='test01@testorg.com',
                        emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US',
                        localesidkey='en_US', profileid = profiles.get('System Administrator').Id,
                        timezonesidkey='America/Los_Angeles', username='test01@testorg.com', CommunityNickname = 'test01');
						
    	insert new List<User>{u1};
        
      	Account acc1 = new Account(Name='Test01', Managing_Director_lu__c = u1.Id);
        insert new List<Account>{acc1};
    
      	Opportunity opp1 = new Opportunity(AccountId = acc1.Id, Name = 'Test Opp 1', StageName = 'Qualified', Submission_Entry__c = FALSE, 
      										Managing_Director_lu__c = u1.Id, Market_Segment__c = 'Managed Care Organization', 
											CloseDateTrigger_30__c = System.today() ,
      										Type = 'Renewal', CloseDate = date.Today()+2 , isMCOOFACQuoteTriggered__c = FALSE );
		
		insert 	opp1;
      	
    }
}


Let us know if this will help you
Melissa HallMelissa Hall
Thanks Amit.  I'm getting an error on line 25 because CloseDateTrigger_30__c is a formula field, and therefore not writable.  It doesn't need to be a formula field though, that's just the only way I could think to get this to trigger correctly because we exclude weekends in our task dates.
Amit Chaudhary 8Amit Chaudhary 8
If that is the formula field then please try below code.

NOTE:- Please post your formual field screen shot so according to formula we can create test data.
 
@isTest
private class OFACMCOQuote_Test 
{
    static testMethod void OFACTask_Test() 
	{
        
    	Map<String, Profile> profiles = new Map<String, Profile>();
        for(Profile p : [select id, name from profile where name IN ('System Administrator')])
		{
            profiles.put(p.Name, p);
        }
        
        User u1 = new User(alias = 'test01', email='test01@testorg.com',
                        emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US',
                        localesidkey='en_US', profileid = profiles.get('System Administrator').Id,
                        timezonesidkey='America/Los_Angeles', username='test01@testorg.com', CommunityNickname = 'test01');
						
    	insert new List<User>{u1};
        
      	Account acc1 = new Account(Name='Test01', Managing_Director_lu__c = u1.Id);
        insert new List<Account>{acc1};
    
      	Opportunity opp1 = new Opportunity(AccountId = acc1.Id, Name = 'Test Opp 1', StageName = 'Qualified', Submission_Entry__c = FALSE, 
      										Managing_Director_lu__c = u1.Id, Market_Segment__c = 'Managed Care Organization', 
      										Type = 'Renewal', CloseDate = date.Today()+2 , isMCOOFACQuoteTriggered__c = FALSE );
		
		insert 	opp1;
      	
    }
}

Let us know if this will help you

Thanks
Amit Chaudhary
 
Sean McMickleSean McMickle

Hi Melissa,

I remember talking to you about you wanting to code for Salesforce at our User Group meeting.  Congrats on writing your first classes to be used in your production environment!  

There is one major glaring issue in your code. You are unnecessarily always running your SOQL and DML statements.  You don't want to run them unless you have to, due to limits. Typically, if you are updating a field on the object in the trigger, you want to do that in a before update. I'm not sure what your binder is doing, so I will avoid that for now, be sure to add it back in later.

You only want to run the classes if you have to. When you begin to expand your code, you could possibly add delete triggers. Without checking to see if your triggers were in the correct context, you would always run the code, even when you don't to.

trigger OFACMCOTriggers on Opportunity (before insert, before update) {
       if(trigger.isBefore && trigger.isInsert) {
            OFACMCOQuote.OFACTask(Trigger.new);
      } else if(trigger.isBefore && trigger.isUpdate) {
            OFACMCOQuote.OFACTask(Trigger.new);
      }
}

Before updates / inserts change field values(of the object in the trigger) without even having to use SOQL or DML! Use this as much as you can!
 
public static void OFACTask(List<Opportunity> oppList){ 
             for(Opportunity o : oppList) {
                   if((o.Type == 'Renewal'  
                       || o.Type == 'Guaranteed Renewal')
                       && !o.isClosed 
                       && o.Market_Segment__c == 'Managed Care Organization'
                       && o.CloseDateTrigger_30__c <= Date.today() 
                       && !o.isMCOOFACQuoteTrigger__c) {

                              o.isMCOOFACQuoteTrigger = true;

                    }
             }
}

For your test class, all you have to do is insert an opportunity that meets those conditions. You will need to post the workflow rule so that we can figure out how to trigger CloseDateTrigger__30__c.  I assume your isClosed happens when the opportunity is closed. You don't have to worry about changing that here, same with explicitly setting MCOOFACQuoteTrigger__c false to begin with, I assume that defaults to false as well.

 
@isTest
private class OFACMCOQuote_Test {

    static testMethod void OFACTask_Test() {
          // Create opportunity;
          Opportunity o = new Opportunity(
          Type = 'Renewal',
          Market_Segment__c = 'Managed Care Organization');

         // Insert opportunity into DB.
        insert o;
         
        // Start the test.
        Test.startTest();
        
        // Select the updated opportunity.
        Opportunity updatedOpportunity = [Select isMCOOFACQuoteTrigger__c from Opportunity where id = : o.id];
        
        // Ensure OFACTask method updated isMCOOFACQuoteTrigger__c to true.
        System.assert(updatedOpportunity.isMCOOFACQuoteTriggered__c, true);
    }
}

Always be sure to assert what changes you are looking for. Here, we are looking to ensure that isMCOOFACQuoteTriggered__c is true, so we check it after we insert the opportunity.


 Here are a few other coding tips ::


 

        Map<String, Profile> profiles = new Map<String, Profile>();
        for(Profile p : [select id, name from profile where name IN ('System Administrator')])
		{
            profiles.put(p.Name, p);
        }

Since you are just trying to use the Id, you can simply do this instead :: 
 
Id profileID = [Select id from Profile where name = 'System Administrator'].id;

When you create your user, you can do this ::
 
User u1 = new User(alias = 'test01', email='test01@testorg.com',
                        emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US',
                        localesidkey='en_US', profileid = profileID,
                        timezonesidkey='America/Los_Angeles', username='test01@testorg.com',                                                  CommunityNickname = 'test01');

When inserting one object, in this case, user, you can simply do this ::
 
insert u1;

You can do the same for account.

Let me know if you have any questions. I am more than happy to help!

Good luck!

-Sean
Melissa HallMelissa Hall
Amit, thank you so much for your updates.  The code is working using that formatting.
Melissa HallMelissa Hall
Sean, oh my gosh, what you've provided me is fantastic.  I've learned so much from this, so much more than interpretting my consultant's code.  

CloseDateTrigger_30__c is a formula field that eliminates weekends.  Formula is: 

CASE(MOD(CloseDate - DATE(1900, 1, 7), 7), 
0, CloseDate-41, 
1, CloseDate-42, 
2, CloseDate-43, 
3, CloseDate-43, 
4, CloseDate-43, 
5, CloseDate-42, 
6, CloseDate-40, 
null)

I'm not sure what I'm doing incorrectly, but I'm getting an error when I run the test.  Here's my updated project.

Apex Class
public class OFACMCOQuote {
	
	//create list of Opps
	public static void OFACTask(List<Opportunity> oppList){
		System.Debug('OFACTask: Entering');
			
		//field update to trigger process
	 	for(Opportunity opp : oppList) {
			if((o.Type == 'Renewal'  
				|| o.Type == 'Guaranteed Renewal')
				&& !o.isClosed 
				&& o.Market_Segment__c == 'Managed Care Organization'
				&& o.CloseDateTrigger_30__c <= Date.today() 
				&& !o.isMCOOFACQuoteTrigger__c) {

					o.isMCOOFACQuoteTrigger = true;
            
	  	}	
	}  					 
}
Apex Trigger
trigger OFACMCOTriggers on Opportunity (before insert, before update) {
       if(trigger.isBefore && trigger.isInsert) {
            OFACMCOQuote.OFACTask(Trigger.new);
      } else if(trigger.isBefore && trigger.isUpdate) {
            OFACMCOQuote.OFACTask(Trigger.new);
      }
}
Apex Test Class
@isTest
private class OFACMCOQuoteTest {
	
	//Verify that OFAC test and notification are triggered
    static testMethod void OFACTaskQuote_Test() {
        
        //Load test Profile
    	Id profileID = [select id from profile where name = 'System Administrator'].id;
        
        //Load test User
        User u1 = new User(alias = 'test01', email='test01@testorg.com',
                        emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US',
                        localesidkey='en_US', profileid = profileID,
                        timezonesidkey='America/Los_Angeles', username='test01@testorg.com', 
                         CommunityNickname = 'test01');
						
    	insert u1;
        
        //Load test Account
      	Account acc1 = new Account(Name='Test01', Managing_Director_lu__c = u1.Id);
        insert acc1;
    
    	//Load test Opportunity
      	Opportunity opp1 = new Opportunity(AccountId = acc1.Id, Name = 'Test Opp 1', StageName = 'Qualified', 
                          Submission_Entry__c = FALSE, Managing_Director_lu__c = u1.Id, 
                          Market_Segment__c = 'Managed Care Organization', Type = 'Renewal', 
                          CloseDate = date.Today()+2 );
		
		insert opp1;
		
		//start testing
		Test.startTest();
		
		//Select the updated opportunity
		Opportunity updatedOpp = [Select isMCOOFACQuoteTriggered__c From Opportunity Where id =: opp1.id];
      	
      	//Ensure OFACTask method updated field
      	System.assert(updatedOpp.isMCOOFACQuoteTriggered__c, true);
    }
}
Error Message:
System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, OFACMCOTriggers: execution of BeforeUpdate

caused by: System.DmlException: Update failed. First exception on row 0 with id 00663000002tWy9AAE; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = 00663000002tWy9) is currently in trigger OFACMCOTriggers, therefore it cannot recursively update itself: []

Class.OFACMCOQuote.OFACTask: line 33, column 1
Trigger.OFACMCOTriggers: line 5, column 1: []
Line 33 is the first line of loading the new Opp, and line 5 is Trigger.new after the IsUpdate.

I also need to trigger this task when Close Date is tomorrow.  I have an additional formula field, and separate code for that action, but I'm starting to wonder if it can be combined into one class.

CloseDateTrigger_1__c = 
CASE(MOD(CloseDate - DATE(1900, 1, 7), 7), 
0, CloseDate-2, 
1, CloseDate-3, 
2, CloseDate-1, 
3, CloseDate-1, 
4, CloseDate-1, 
5, CloseDate-1, 
6, CloseDate-1, 
null)

Thanks!
Sean McMickleSean McMickle
Hmm, I don't see a line 33 in OFACMCOQuote.OFACTask (it appears to only go to 20 lines). Are you attempting an update statement after this block?
 
public class OFACMCOQuote {
	
	//create list of Opps
	public static void OFACTask(List<Opportunity> oppList){
		System.Debug('OFACTask: Entering');
			
		//field update to trigger process
	 	for(Opportunity opp : oppList) {
			if((o.Type == 'Renewal'  
				|| o.Type == 'Guaranteed Renewal')
				&& !o.isClosed 
				&& o.Market_Segment__c == 'Managed Care Organization'
				&& o.CloseDateTrigger_30__c <= Date.today() 
				&& !o.isMCOOFACQuoteTrigger__c) {

					o.isMCOOFACQuoteTrigger = true;
            
	  	}	
	}  					 
}

 
Melissa HallMelissa Hall
Error is on my end.  I was missing a curley brace, and Eclipse wasn't throwing an error to let me know it wasn't saving to the server.  After I fixed that, I encountered another error, but I'm going to try to problem solve and see if I can learn from my mistake.
Sean McMickleSean McMickle
Awesome, good luck!