[SalesForce] System.AsyncException: The Apex job named “Name of the Job” is already scheduled for execution

I have batch class and a scheduler as follows ,I am facing following error while executing Test Class.

System.AsyncException: The Apex job named "Name of the Job" is
already scheduled for execution.

Batch Class:

global class BatchUpdateLegalEntityQ1 implements Database.Batchable<sObject> { 
String query;
global BatchUpdateLegalEntityQ1() {
query = 'SELECT Id,Financial_Quarter__c,Legal_Entity__c From Legal_Entity_Contact__c ' + 
'WHERE (CSAT_Respondent__c = \'Yes\') ' + 'AND (Financial_Quarter__c != \'Q1\') ' + 'LIMIT 400';       
}

//Start the batch  
global Database.QueryLocator start(Database.BatchableContext BC) {      
return Database.getQueryLocator(query);
}

//Execute the batch 
global void execute(Database.BatchableContext BC, List<Legal_Entity_Contact__c> lecList) {       
System.debug('*****lecList '+lecList); 

for(integer i=0;i<lecList.size();i++) { 
lecList[i].Financial_Quarter__c = 'Q1'; 
lecList[i].Feedback_Request_Type__c = 'Automatic';               
}
if(lecList.size()>0) {
update lecList;
}      
}

//Finish the batch 
global void finish(Database.BatchableContext BC) {
List<Legal_Entity_Contact__c> legalEntityId =  new List<Legal_Entity_Contact__c>();
legalEntityId = [SELECT Id From Legal_Entity_Contact__c WHERE CSAT_Respondent__c = 'Yes' AND Financial_Quarter__c != 'Q1' LIMIT 1];

if (!legalEntityId.isEmpty()) {
//CAST mails will be triggered for Q1 quarter via Schedular
Integer daynow = system.now().day()+1;
String myString = String.valueOf(date.today()+1);
String day = string.valueOf(daynow);
String month = string.valueOf(system.now().month());
String year = string.valueOf(system.now().year());
String strSchedule = '0 15 00'+ ' ' + day + ' ' + month + ' ?' + ' ' + year;
System.schedule('CSAT for Q1_' + myString, strSchedule, new ScheduleBatchUpdateLegalEntityQ1());          

} else {
//New Apex schedular will be scheduled for Q1 quarter of next year
Integer yearNow = system.now().year()+1;
String year = string.valueOf(yearNow);
String strSchedule = '0 15 00 10 02 ? ' + year;            
System.schedule('CSAT for Q1_' + year, strSchedule, new ScheduleBatchUpdateLegalEntityQ1());             
System.debug('*****strSchedule ' + strSchedule);           

}
}
}

Test Class:

@isTest
public class TestBatchUpdateLegalEntityQ1{
    static testMethod void BatchUpdateLegalEntityQ1(){

        Account oppaccount = new Account(Name = 'Account');
        oppaccount.Customer_Type__c = 'Carriers';
        System.debug(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Customer - Verified').getRecordTypeId());
        oppaccount.RecordTypeId =  Schema.SObjectType.Account.getRecordTypeInfosByName().get('Customer - Verified').getRecordTypeId();
        oppaccount.Industry ='Agriculture';
        insert oppaccount;    

        Legal_Entity__c legent = new Legal_Entity__c();
        system.debug('The Chosen Id is ' + oppaccount.Id);
        legent.Account__c = oppaccount.Id;
        legent.Name = 'test';
        legent.Credit_Rating__c = 'Green';
        legent.Industry__c = 'Education';
        legent.Sub_Industry__c = 'Board/University';
        legent.Registered_Address_Country__c='United Kingdom';
        legent.Website_address__c = 'test1';
        legent.Registration_Number__c = '12233445';
        legent.Registered_Address_Zip_Postal_Code__c='411028';
        legent.Legal_Entity_Owner__c = UserInfo.getUserId();
        legent.PO_Required__c='No';
        insert legent;

        Contact c = new Contact();
        c.FirstName='Contact';
        c.LastName='Test Contact';
        c.AccountId=oppaccount.Id;
        c.CSAT_Respondent_Type__c='Account Manager';
        c.Q_CSAT_Respondent__c = 'Yes';
        c.Role__c='Employee';
        c.Email='abc@gmail.com';
        c.Legal_Entity__c = legent.Id;
        insert c;

        Legal_Entity_Contact__c lec = new Legal_Entity_Contact__c();
        lec.Legal_Entity__c=legent.id;
        lec.Contact__c = c.Id;
        lec.Financial_Quarter__c ='Q2';
        insert lec;

        Test.startTest();
        Database.executeBatch(new BatchUpdateLegalEntityQ1());     
        ScheduleBatchUpdateLegalEntityQ1 schUpdateLegal1 = new ScheduleBatchUpdateLegalEntityQ1();
        String sch = '0 0 23 * * ?';
        system.schedule('schUpdateLegalone', sch, schUpdateLegal1);        
        Test.stopTest();
    }
}

Best Answer

If you have the scheduled class already running in the real system, that clashes with the one you are trying to run from your test. An example of where test-isolation is a bit leaky in SF.

In general, it's worth sticking the current time in milliseconds on the end of your scheduled job names. That solves this problem and also another problem where sandboxes don't always start their scheduled jobs properly. On the sandbox, you can end up with the scheduled job not running but still existing, so stopping you from manually restarting it.

System.schedule('CSAT for Q1_' + myString + '-' + System.currentTimeMillis(), strSchedule, new ScheduleBatchUpdateLegalEntityQ1());          

You'll notice various managed packages (e.g. the Pardot connector) doing the same thing.