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
Stuart HARRISONStuart HARRISON 

Test class for enquiry apex class

I have an Apex class that runs based on a database enquiry and creates new opportunities (clones) where certain criteria are met. Im unsure how to build a test script for this ? Ive done all my testing in sandbox by running through the developer portal. For pushing to Production I now need a test script. I dont want loads of new opportunities created in production so Im not sure how I do this ? My Apex code is below. Any pointers appreciated 0 its my first Apex Class change.

global class CreateRenewal implements Schedulable { 
    global void execute(SchedulableContext ctx) { 

        List<Opportunity> InList = [Select 
        AccountID,
        Amount,
        CloseDate,
        CreatedByID,
        Description,
        ExpectedRevenue,
        ForecastCategoryName,
        LeadSource,
        NextStep,
        CurrencyIsoCode,
        Name,
        OwnerID,
        RecordTypeID,
        Pricebook2ID,
        CampaignID,
        IsPrivate,
        Probability,
        TotalOpportunityQuantity,
        IqScore,
        StageName,
        Type,
        Compliance__c,
        Coverholder_Commission__c,
        Local_Insurer_Commission__c,
        Local_Taxes__c,
        Reinsurance_broker_commission__c,
        Retail_broker_commission__c,
        Sum_Insured__c,
        Account_Contact__c,
        Additional_Amount_in_Oppty_Currency__c,
        Additional_Countries__c,
        Additional_tax_commission_cost_descripti__c,
        AXA_ASR_Pricing_Model_Version__c,
        Business_Type_Class__c,
        Cedents_retention__c,
        Cedents_Retention_Amount__c,
        Channel__c,
        Coinsurances_Commissions_from_Brokers__c,
        Coinsurances_Commissions_to_Brokers__c,
        Coinsurances_Commissions_to_Coverholder__c,
        Coinsurances_Percentage__c,
        Coinsurances_Premium__c,
        Contract_Type__c,
        Coverholder__c,
        Days_to_Quote_Released__c,
        DB_Competitor__c,
        Direct_Contact__c,
        Direct_Source__c,
        Estimated_S6130_GNP__c,
        Fast_track__c,
        Global_GNP__c,
        Insured_Period_From__c,
        Insured_Period_To__c,
        Intermediary_Commission__c,
        Intermediary_Account__c,
        Intermediary_Contact__c,
        Intermediary_Reinsurance_Broker__c,
        Intermediary_Reinsurance_Contact__c,
        Layer__c,
        LoB__c,
        Local_Insurer__c,
        Local_Insurer_Commission_Percentage__c,
        Local_Insurer_Contact__c,
        Lost_Cancel_Reason__c,
        Lost_Cancelled_Reason_Comment__c,
        Lost_Due_to_Pricing_amount__c,
        Lost_Due_to_Pricing_currency__c,
        Non_Renewable__c,
        Opportunity_Channel__c,
        P_Coverholder_Commission__c,
        P_Intermediary_Commission__c,
        P_Local_Insurer_Commission__c,
        P_Local_Taxes__c,
        Policy__c,
        Post_Underwriting_Compliance__c,
        Pre_Issue_Compliance__c,
        Pre_Underwriting_Compliance__c,
        Previously_won_or_lost__c,
        Pricing_Model_Source__c,
        Primary_Country__c,
        Proportional__c,
        P_Syndicate_Gross_Premium__c,
        P_Syndicate_Premium__c,
        Quote_Released_Date__c,
        Reinsurance_Facultative__c,
        Reinsurer_Taxes__c,
        Reinsurer_Taxes_Amount__c,
        Renewal_Created__c,
        Renewal_Indicator__c,
        Renewal_Information__c,
        Rest_of_World__c,
        reviewScope__c,
        Risk_Category__c,
        AXA_GNP__c,
        S1084_S6130_Percentage__c,
        S6130_Coverholder_Commission__c,
        S6130_Coverholder_Commission_Amount__c,
        Syndicate_GGP__c,
        S6130_Line_Size__c,
        S6130_Local_Insurer_Commission__c,
        S6130_Local_Insurer_Commission_Amount__c,
        S6130_Local_Taxes__c,
        S6130_Local_Taxes_Amount__c,
        Syndicate_Percentage__c,
        S6130_Reinsurance_Broker_Commission__c,
        S6130_Reinsurance_Broker_Commission_Amou__c,
        S6130_Retail_Broker_Commission__c,
        S6130_Retail_Broker_Commission_Amount__c,
        Short_Name__c,
        Step__c,
        Subject_to_NDA__c,
        Sub_Status__c,
        Underwriter__c,
        UW_Reference__c,
        Renewed_Opportunity_Link__c,
        Renewal_Opportunity_Link__c,
        Renewal_Opportunity__c
        
        From Opportunity 
        where Opportunity.Insured_Period_to__c <= NEXT_90_DAYS 
        AND Opportunity.LoB__c = 'Property'
        AND Opportunity.Insured_Period_to__c > :date.today()
        AND Opportunity.Renewal_Created__c != 'YES'
        AND (opportunity.StageName = 'Closed - Won' OR opportunity.StageName = 'Closed - Lost')]; 
        
        
        List<Opportunity> newOpps=new List<Opportunity>();

        for(Opportunity c: InList){
        
    if (c.StageName == 'Closed - Won'){
        Opportunity opp = c.clone();

            opp.StageName = 'New';
            opp.Renewal_Indicator__c = true;
            Opp.Insured_period_from__c = c.Insured_period_to__c;
            Opp.Insured_period_to__c = Opp.Insured_period_from__c.adddays(c.Insured_period_from__c.daysbetween(c.Insured_period_to__c));
            Opp.CloseDate = Opp.Insured_period_from__c.addmonths(-1);
            opp.Name = Opp.Insured_period_from__c.year() + '_' + c.Name.substringafter('_');
            c.Renewal_Opportunity__c = opp.name;    
            Opp.Short_name__c = c.Short_name__c;
            Opp.OwnerID = c.CreatedByID;
            c.Renewal_Created__c = 'Yes';
            Opp.Previously_won_or_lost__c = 'Won';
            Opp.Renewed_Opportunity_Link__c = c.Id;
            Opp.Renewal_Information__c = 'Original S6130 Line Size was : ' + Opp.S6130_Line_Size__c;
            newOpps.add(Opp);
            c.Renewal_Opportunity_Link__c = opp.Id;
            }
    if (c.StageName == 'Closed - Lost')
    {
        Opportunity opp = c.clone();

            opp.StageName = 'New';
            opp.Renewal_Indicator__c = true;
            Opp.Insured_period_from__c = c.Insured_period_to__c;
            Opp.Insured_period_to__c = Opp.Insured_period_from__c.adddays(c.Insured_period_from__c.daysbetween(c.Insured_period_to__c));
            Opp.CloseDate = Opp.Insured_period_from__c.addmonths(-1);
            opp.Name = Opp.Insured_period_from__c.year() + '_' + c.Name.substringafter('_');
            c.Renewal_Opportunity__c = opp.name;    
            Opp.Short_name__c = c.Short_name__c;
            Opp.OwnerID = c.CreatedByID;
            c.Renewal_Created__c = 'Yes';
            Opp.Previously_won_or_lost__c = 'Lost';
            Opp.Renewed_Opportunity_Link__c = c.Id;
            Opp.Renewal_Information__c = 'Lost Reason : ' + c.Lost_Cancel_Reason__c + ' - comment : ' + c.Lost_Cancelled_Reason_Comment__c + ' - Pricing : ' + c.Lost_Due_to_Pricing_Currency__c + ' ' + c.Lost_Due_to_Pricing_amount__c;
            Opp.Lost_Cancel_Reason__c = null;
            Opp.Lost_Cancelled_Reason_Comment__c = null;
            Opp.Lost_Due_to_Pricing_Currency__c = null;
            Opp.Lost_Due_to_Pricing_amount__c = null;
            newOpps.add(Opp);
            c.Renewal_Opportunity_Link__c = opp.Id;
            }
       if(!InList.isEmpty()) { 
            update InList; 
        } 
        }
       insert newOpps;
       
        List<Messaging.SingleEmailMessage> sendEmailList = new List<Messaging.SingleEmailMessage>();
        Messaging.SingleEmailMessage email;
        for(Opportunity opp : newOpps){
            email = new Messaging.SingleEmailMessage(); 
            string [] toaddress= New string[]{'stuart.harrison@axa.com'}; 
            email.setSubject('Renewal Opportunity - ' + opp.name); 
            email.setHTMLBody('A new renewal opportunity has been assigned to you : ' + opp.name + '     (link - '+  
                              URL.getSalesforceBaseUrl().toExternalForm()+'/'+ opp.id +' )' +
                              + '<br/>'  + 
                              '<br/>' + 'The previous opportunity was ' + Opp.Previously_won_or_lost__c 
                              + '     (link - '+  
                              URL.getSalesforceBaseUrl().toExternalForm()+'/'+ opp.Renewed_Opportunity_Link__c +' )' +
                              + '<br/>' + ' and has an insured period to : ' + opp.Insured_period_from__c
                              + '<br/>' + '<br/>' + 'Details from the previous Opportunity : ' + '<br/>' + '<br/>' + Opp.Renewal_Information__c); 
            email.setToAddresses(toaddress);
            sendEmailList.add(email);
        }
        if(sendEmailList.size() > 0) {
            Messaging.sendEmail(sendEmailList);
        }

     }
           global void finish(Database.BatchableContext BC)
     {
    } 
}
Best Answer chosen by Stuart HARRISON
Steven NsubugaSteven Nsubuga
yeah, remove the "public".

All Answers

Steven NsubugaSteven Nsubuga
Hi Harrison,
the easier option would be for me to paste the test code here but I suggest you check out a tutorial on trailhead to master the testing principles for scheduled apex. 
See here https://trailhead.salesforce.com/en/modules/asynchronous_apex/units/async_apex_scheduled#Tdxn4tBKheading7
Stuart HARRISONStuart HARRISON
Hi Steven,

Ive read loads of articles but im still not sure about my specific scenario. I dont need to create any test data in production as there are plenty of items that match the criteria. I simply want the apex class to run but only create test output (cloned opportunities). Is this possible or do i need to build entire test cases in production first ?
Steven NsubugaSteven Nsubuga
Hi Stuart,
you definitely need to create test data for use in testing. It is a best principle to always have self contained tests, tests that do not rely on existing data within a Salesforce instance. 
For your specific scenario, you must create some opportunities that meet the criteria of the query in your execute method.

here is a sketch of the expected format of the required test class
@isTest
public class CreateRenewalTest{
	
	@isTest public static  void testExecute(){

		Test.startTest();
		
		Account testAccount = new Account(Name='Test Account');
        insert testAccount;
		
		List<Opportunity> oppList = new List<Opportunity>();
		
		for (integer i = 1; i < 5; i++) {
			Opportunity opp = new Opportunity();
			opp.Name = 'Test Opportunity '+i;
			opp.AccountId = testAccount.Id,
            opp.Insured_Period_to__c = date.today().addDays(45+i);      
            opp.StageName = 'Closed - Won';
            if (i < 3) {
                opp.StageName = 'Closed - Lost';
            }
            opp.Insured_Period_to__c = 'en_US';
            opp.LoB__c = 'Property';
			opp.Renewal_Created__c = 'NO';
			// populate all the fields you need
			
			oppList.add(opp);  
		}
		insert oppList;

		// This test runs a scheduled job at midnight Sept. 3rd. 2022
		public static String CRON_EXP = '0 0 0 3 9 ? 2022';
		// Schedule the test job
		String jobId = System.schedule('CreateRenewalTest', CRON_EXP, new CreateRenewal());
		
		// Get the information from the CronTrigger API object 
		CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger WHERE id = :jobId]; 
		// Verify the expressions are the same System.assertEquals(CRON_EXP, ct.CronExpression); 
		// Verify the job has not run 
		System.assertEquals(0, ct.TimesTriggered); 
		
		
		Test.stopTest();
	}
}

 
Stuart HARRISONStuart HARRISON
Many thanks - ive added in the mandatory data that I need but am seeing a message "Error: Compile Error: public is not allowed on locals at line 45 column 29". This seems to be relating to the line "        public static String CRON_EXP = '0 0 0 3 9 ? 2022';"
Steven NsubugaSteven Nsubuga
yeah, remove the "public".
This was selected as the best answer
Stuart HARRISONStuart HARRISON
Thanks for your help :)
Steven NsubugaSteven Nsubuga
My pleasure Stuart!!
Stuart HARRISONStuart HARRISON
Hi Steven - one last bit of help please ? Ive sorted the test script to have enough coverage (86%) and it runs - but seems to loop. When i check the coverage im getting red on the final line "        global void finish(Database.BatchableContext BC)" which is why i assume it never finishes. If i execute the apex in debug mode it runs and finishes fine.
Steven NsubugaSteven Nsubuga
Hi Stuart, it is strange that it does not hit the finish method!! 
Could you add a couple of System.debug() statements in the execute and finish methods to track what happens when you run the test class?