You need to sign in to do that
Don't have an account?
Arturo Alamilla
Batch Class Test to Production problem.
Hello everybody.
I'm a new salesforce developer, and i'm facin my first real world problem in my company.
We have a custom object named "Solicitudes__c", is the detail side of a master relationship of another custom object.
I was asked to calculate the time between stages (Picklist field named "Etapas_de_solicitud__c" with 10 values).
My solution is use History object records to calculate the first date to enter one stage, and the last day touching that same stage for every stage. I had to create some sample records and move them through all stages.
Later i came out with this apex class:
Then i came out with an batch apex class:
And create a Test class:
The problem is that when i'm trying to validate in production i see this problem: "System.UnexpectedException: No more than one executeBatch can be called from within a test method. Please make sure the iterable returned from your start method matches the batch size, resulting in one executeBatch invocation.
Stack Trace: External entry point"
Any suggestions?
I'm a new salesforce developer, and i'm facin my first real world problem in my company.
We have a custom object named "Solicitudes__c", is the detail side of a master relationship of another custom object.
I was asked to calculate the time between stages (Picklist field named "Etapas_de_solicitud__c" with 10 values).
My solution is use History object records to calculate the first date to enter one stage, and the last day touching that same stage for every stage. I had to create some sample records and move them through all stages.
Later i came out with this apex class:
public with sharing class SolicitudesTiempos { public static void tiempos(List<Solicitudes__c> solicitudes) { //transform the List to Set of Ids set<id> solicitudesIds = new set<Id>(); for(solicitudes__c s : solicitudes){ solicitudesIds.add(s.id); } //list used to update the Solicitudes__c records lateer List<Solicitudes__c> solicitudesActualizar = new List<Solicitudes__c>(); //gather all Solicitudes__History records. list<Solicitudes__History> historialBuscado = [SELECT ParentId, NewValue, OldValue, CreatedDate FROM Solicitudes__History WHERE ParentId =: solicitudesIds AND Field = 'Etapas_de_Solicitud__c' WITH SECURITY_ENFORCED ORDER BY CreatedDate ASC]; // lists to store the history changes, accordingly. list<Solicitudes__History> historialCotizacion = new list<Solicitudes__History>(); list<Solicitudes__History> historialAceptacion = new list<Solicitudes__History>(); list<Solicitudes__History> historialPreanalisis = new list<Solicitudes__History>(); list<Solicitudes__History> historialDocumentos = new list<Solicitudes__History>(); list<Solicitudes__History> historialCarga = new list<Solicitudes__History>(); list<Solicitudes__History> historialPendienteAnalizar = new list<Solicitudes__History>(); list<Solicitudes__History> historialComite = new list<Solicitudes__History>(); list<Solicitudes__History> historialCondicionada = new list<Solicitudes__History>(); list<Solicitudes__History> historialAutorizada = new list<Solicitudes__History>(); list<Solicitudes__History> historialPendientedeFirma = new list<Solicitudes__History>(); // loop throughout all solicitudes__history to store the appropiate history record to a list. for(Solicitudes__History s : historialBuscado){ if(s.NewValue == 'Cotización' || s.OldValue == 'Cotización'){ historialCotizacion.add(s); } } for(Solicitudes__History s : historialBuscado){ if(s.NewValue == 'Aceptación' || s.OldValue == 'Aceptación'){ historialAceptacion.add(s); } } for(Solicitudes__History s : historialBuscado){ if(s.NewValue == 'Preanálisis' || s.OldValue == 'Preanálisis'){ historialPreanalisis.add(s); } } for(Solicitudes__History s : historialBuscado){ if(s.NewValue == 'Documentos' || s.OldValue == 'Documentos'){ historialDocumentos.add(s); } } for(Solicitudes__History s : historialBuscado){ if(s.NewValue == 'Aviso a sebas' || s.OldValue == 'Aviso a sebas'){ historialCarga.add(s); } } for(Solicitudes__History s : historialBuscado){ if(s.NewValue == 'pendiente de analizar' || s.OldValue == 'pendiente de analizar'){ historialPendienteAnalizar.add(s); } } for(Solicitudes__History s : historialBuscado){ if(s.NewValue == 'comite' || s.OldValue == 'comite'){ historialComite.add(s); } } for(Solicitudes__History s : historialBuscado){ if(s.NewValue == 'condicionado' || s.OldValue == 'condicionado'){ historialCondicionada.add(s); } } for(Solicitudes__History s : historialBuscado){ if(s.NewValue == 'autorizada' || s.OldValue == 'autorizada'){ historialAutorizada.add(s); } } for(Solicitudes__History s : historialBuscado){ if(s.NewValue == 'pendiente de firma' || s.OldValue == 'pendiente de firma'){ historialPendientedeFirma.add(s); } } // loop to calcule every Solicitudes__c record time on each stage. for(Id s : solicitudesIds){ Decimal tiempoCotizacion = SolicitudesTiempos.calcularTiempo(historialCotizacion, s); Decimal tiempoAceptacion = SolicitudesTiempos.calcularTiempo(historialAceptacion, s); Decimal tiempoPreanalisis = SolicitudesTiempos.calcularTiempo(historialPreanalisis, s); Decimal tiempoDocumentos = SolicitudesTiempos.calcularTiempo(historialDocumentos, s); Decimal tiempoCarga = SolicitudesTiempos.calcularTiempo(historialCarga, s); Decimal tiempoPendienteAnalizar = SolicitudesTiempos.calcularTiempo(historialPendienteAnalizar, s); Decimal tiempoComite = SolicitudesTiempos.calcularTiempo(historialComite, s); Decimal tiempoCondicionado = SolicitudesTiempos.calcularTiempo(historialCondicionada, s); Decimal tiempoAutorizada = SolicitudesTiempos.calcularTiempo(historialAutorizada, s); Decimal tiempoPendienteFirma = SolicitudesTiempos.calcularTiempo(historialPendientedeFirma, s); //store each calculation to the record's field and add it to a collection to update later. Solicitudes__c solicitud = new Solicitudes__c(Id = s, Tiempo_cotizacion__c=tiempoCotizacion, Tiempo_Aceptacion__c=tiempoAceptacion, Tiempo_preanalisis__c=tiempoPreanalisis, Tiempo_Documentos__c=tiempoDocumentos, Tiempo_Carga__c=tiempoCarga, Tiempo_Por_analizar__c=tiempoPendienteAnalizar, Tiempo_Comite__c=tiempoComite, Tiempo_Condicionada__c=tiempoCondicionado, Tiempo_Autorizada__c=tiempoAutorizada, Tiempo_Pendiente_Firma__c=tiempoPendienteFirma); //add the new record to a collection to update later. solicitudesActualizar.add(solicitud); } //update the records update solicitudesActualizar; } //method to calculate time between stages. private static Decimal calcularTiempo (list<Solicitudes__History> historial, Id solicitudId){ if(historial.size()>0 && historial != null){ dateTime date1; dateTime date2; Decimal minutos; for(Solicitudes__History hist : historial){ if(hist.ParentId == solicitudId && date1 == null){ date1 = hist.CreatedDate; }else if(hist.ParentId == solicitudId && date1 != null){ date2 = hist.CreatedDate; } } if(date1 != null && date2 != null){ Long firstDate = date1.getTime(); Long finalDate = date2.getTime(); Decimal segundos = (finalDate-firstDate)/1000; minutos = segundos/60; return minutos; }else{ return 0.00; } }else{ return 0.00; } } }
Then i came out with an batch apex class:
public class SolicitudesTiemposBatch implements Database.Batchable<SObject> { public Database.QueryLocator start(Database.BatchableContext bc) { String query = 'SELECT Id FROM Solicitudes__c '+ 'WHERE CreatedDate >= 2022-01-01T00:00:00Z '+ 'ORDER BY CreatedDate ASC'; return DataBase.getQueryLocator(query); } public void execute(Database.BatchableContext bc, List<Solicitudes__c> scope){ SolicitudesTiempos.tiempos(scope); } public void finish(database.BatchableContext bc){ } }
And create a Test class:
@isTest public class SolicitudesTiemposBatchTest { @isTest(SeeAllData=true) static void test(){ Test.startTest(); SolicitudesTiemposBatch solicitudesBatch = new SolicitudesTiemposBatch(); Database.executeBatch(solicitudesBatch, 200); Test.stopTest(); System.assertEquals(199,[SELECT count() FROM Solicitudes__C], '199 solicitudes'); } }And i get enough coverage to deploy production.
The problem is that when i'm trying to validate in production i see this problem: "System.UnexpectedException: No more than one executeBatch can be called from within a test method. Please make sure the iterable returned from your start method matches the batch size, resulting in one executeBatch invocation.
Stack Trace: External entry point"
Any suggestions?
You need to use only @isTest and mock your data. That means you need to create a loop that generates the 199 solicitudes and his relationships.
Maybe this article can help you: https://jayakrishnasfdc.wordpress.com/2021/01/02/apex-test-class-for-batch-apex/
I hope this help you. In addition, let me know if you speak spanish to give more detail in that language.
All the best for you!
All Answers
You need to use only @isTest and mock your data. That means you need to create a loop that generates the 199 solicitudes and his relationships.
Maybe this article can help you: https://jayakrishnasfdc.wordpress.com/2021/01/02/apex-test-class-for-batch-apex/
I hope this help you. In addition, let me know if you speak spanish to give more detail in that language.
All the best for you!
And yes, i do speak spanish.