Seguramente ya le habéis echado un vistazo a las notas de la última Release de Salesforce, Spring ’15.
En esta reléase aparece una nueva notación @testSetup.
Esta nueva notación va asociada a métodos en los cuales serán creado los datos que mas adelante los diferentes métodos test existentes en la clase pueden utilizar durante su ejecución.
Lo que conseguimos entonces es un código mucho más limpio sin repetición de creación de datos por cada método test ejecutado, y si ya esa creación se había implementado usando un método especifico para dicha de creación de datos siendo llamado desde el método test a ejecutar, ahora esta llamada ya no será necesaria.
Podemos tener mas de un método con @testSetup en una clase, pero lo que no podemos asegurar es el orden en el que se ejecutarán. Luego debemos hacer la creación de datos independiente.
La siguiente pregunta que nos puede cruzar por la mente es volúmenes. ¿Quiere decir esto que se han incrementado?, ¿que la creación de datos no ocurre en el mismo contexto de ejecución de nuestro método test?
Esta vez tengo que decir que tristemente, la creación de datos ocurre en el mismo contexto con lo cual no hay incremento de limites.
Si queremos que estos aumenten debemos como ya hacíamos anteriormente usar Test.startTest() para ello.
Luego la mayor ventaja de esta notación es ayudarnos a tener un código más limpio, no repeticiones de código y hacer una carga de datos compatible para todos los métodos test de la clase.
A continuación os dejo una clase test y su correspondiente log para que veáis el orden de ejecución y limites.
Hasta Pronto!
@isTest private class MyTest { @testSetup static void createData() { System.debug('Enter in createData Method1: testSetup::'+Limits.getDMLStatements()+'::'+Limits.getLimitDMLStatements()); Account newAccount = new Account(Name='Account1'); insert newAccount; System.debug('Enter in createData Method2: testSetup::'+Limits.getDMLStatements()+'::'+Limits.getLimitDMLStatements()); } static testMethod void testData1() { Test.startTest(); System.debug('Enter in testData1::'+Limits.getDMLStatements()+'::'+Limits.getLimitDMLStatements()); Account newAccount = [Select Name From Account]; System.assertEquals('Account1', newAccount.Name); System.debug('Enter in testData12::'+Limits.getDMLStatements()+'::'+Limits.getLimitDMLStatements()); Test.stopTest(); } static testMethod void testData2() { System.debug('Enter in testData2::'+Limits.getDMLStatements()+'::'+Limits.getLimitDMLStatements()); Account newAccount = [Select Name From Account]; System.assertEquals('Account1', newAccount.Name); System.debug('Enter in testData22::'+Limits.getDMLStatements()+'::'+Limits.getLimitDMLStatements()); } }
El Orden de Ejecución ha sido entonces:
1. createData
2. testData1
3. testData2
Debug Log:
33.0 APEX_CODE,DEBUG;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;WORKFLOW,INFO 17:14:58.094 (94312697)|EXECUTION_STARTED 17:14:58.094 (94394637)|CODE_UNIT_STARTED|[EXTERNAL]|01pB0000000HolG|myTest.createData 17:14:58.094 (94810652)|METHOD_ENTRY|[2]|01pB0000000HolG|myTest.myTest() 17:14:58.094 (94821557)|METHOD_EXIT|[2]|myTest 17:14:58.094 (94952980)|SYSTEM_METHOD_ENTRY|[7]|Limit.getDmlStatements() 17:14:58.095 (95001929)|SYSTEM_METHOD_EXIT|[7]|Limit.getDmlStatements() 17:14:58.095 (95048420)|SYSTEM_METHOD_ENTRY|[7]|String.valueOf(Object) 17:14:58.095 (95070797)|SYSTEM_METHOD_EXIT|[7]|String.valueOf(Object) 17:14:58.095 (95085582)|SYSTEM_METHOD_ENTRY|[7]|Limit.getLimitDmlStatements() 17:14:58.095 (95097514)|SYSTEM_METHOD_EXIT|[7]|Limit.getLimitDmlStatements() 17:14:58.095 (95114023)|SYSTEM_METHOD_ENTRY|[7]|String.valueOf(Object) 17:14:58.095 (95129705)|SYSTEM_METHOD_EXIT|[7]|String.valueOf(Object) 17:14:58.095 (95151621)|SYSTEM_METHOD_ENTRY|[7]|System.debug(ANY) 17:14:58.095 (95160524)|USER_DEBUG|[7]|<b>DEBUG|Enter in createData Method1: testSetup::0::150</b> 17:14:58.095 (95167447)|SYSTEM_METHOD_EXIT|[7]|System.debug(ANY) 17:14:58.096 (96543628)|DML_BEGIN|[9]|Op:Insert|Type:Account|Rows:1 17:14:58.183 (183682155)|DML_END|[9] 17:14:58.183 (183738203)|SYSTEM_METHOD_ENTRY|[10]|Limit.getDmlStatements() 17:14:58.183 (183780544)|SYSTEM_METHOD_EXIT|[10]|Limit.getDmlStatements() 17:14:58.183 (183815295)|SYSTEM_METHOD_ENTRY|[10]|String.valueOf(Object) 17:14:58.183 (183835500)|SYSTEM_METHOD_EXIT|[10]|String.valueOf(Object) 17:14:58.183 (183847113)|SYSTEM_METHOD_ENTRY|[10]|Limit.getLimitDmlStatements() 17:14:58.183 (183866985)|SYSTEM_METHOD_EXIT|[10]|Limit.getLimitDmlStatements() 17:14:58.183 (183884620)|SYSTEM_METHOD_ENTRY|[10]|String.valueOf(Object) 17:14:58.183 (183900710)|SYSTEM_METHOD_EXIT|[10]|String.valueOf(Object) 17:14:58.183 (183919237)|SYSTEM_METHOD_ENTRY|[10]|System.debug(ANY) 17:14:58.183 (183926903)|USER_DEBUG|[10]|DEBUG|<b>Enter in createData Method2: testSetup::1::150</b><b> </b>17:14:58.183 (183932859)|SYSTEM_METHOD_EXIT|[10]|System.debug(ANY) 17:14:58.173 (183961154)|CUMULATIVE_LIMIT_USAGE 17:14:58.173|LIMIT_USAGE_FOR_NS|(default)| Number of SOQL queries: 0 out of 100 Number of query rows: 0 out of 50000 Number of SOSL queries: 0 out of 20 Number of DML statements: 1 out of 150 Number of DML rows: 1 out of 10000 Maximum CPU time: 0 out of 10000 Maximum heap size: 0 out of 6000000 Number of callouts: 0 out of 100 Number of Email Invocations: 0 out of 10 Number of future calls: 0 out of 50 Number of queueable jobs added to the queue: 0 out of 50 Number of Mobile Apex push calls: 0 out of 10 17:14:58.173|CUMULATIVE_LIMIT_USAGE_END 17:14:58.183 (183993101)|CODE_UNIT_FINISHED|myTest.createData 17:14:58.185 (185131883)|EXECUTION_FINISHED 17:14:58.194 (194178721)|EXECUTION_STARTED 17:14:58.194 (194189708)|CODE_UNIT_STARTED|[EXTERNAL]|01pB0000000HolG|myTest.testData1 17:14:58.194 (194429563)|METHOD_ENTRY|[2]|01pB0000000HolG|myTest.myTest() 17:14:58.194 (194439177)|METHOD_EXIT|[2]|myTest 17:14:58.194 (194581006)|SYSTEM_METHOD_ENTRY|[14]|system.Test.startTest() 17:14:58.196 (196410911)|SYSTEM_METHOD_EXIT|[14]|system.Test.startTest() 17:14:58.196 (196436313)|SYSTEM_METHOD_ENTRY|[15]|Limit.getDmlStatements() 17:14:58.196 (196533282)|SYSTEM_METHOD_EXIT|[15]|Limit.getDmlStatements() 17:14:58.196 (196565724)|SYSTEM_METHOD_ENTRY|[15]|String.valueOf(Object) 17:14:58.196 (196584800)|SYSTEM_METHOD_EXIT|[15]|String.valueOf(Object) 17:14:58.196 (196599347)|SYSTEM_METHOD_ENTRY|[15]|Limit.getLimitDmlStatements() 17:14:58.196 (196611356)|SYSTEM_METHOD_EXIT|[15]|Limit.getLimitDmlStatements() 17:14:58.196 (196627750)|SYSTEM_METHOD_ENTRY|[15]|String.valueOf(Object) 17:14:58.196 (196643767)|SYSTEM_METHOD_EXIT|[15]|String.valueOf(Object) 17:14:58.196 (196662091)|SYSTEM_METHOD_ENTRY|[15]|System.debug(ANY) 17:14:58.196 (196668968)|USER_DEBUG|[15]|DEBUG|<b>Enter in testData1::0::150</b><b> </b>17:14:58.196 (196674433)|SYSTEM_METHOD_EXIT|[15]|System.debug(ANY) 17:14:58.196 (196828389)|SOQL_EXECUTE_BEGIN|[16]|Aggregations:0|SELECT Name FROM Account 17:14:58.207 (207955957)|SOQL_EXECUTE_END|[16]|Rows:1 17:14:58.208 (208227438)|SYSTEM_METHOD_ENTRY|[17]|System.assertEquals(ANY, ANY) 17:14:58.208 (208283470)|SYSTEM_METHOD_EXIT|[17]|System.assertEquals(ANY, ANY) 17:14:58.208 (208299244)|SYSTEM_METHOD_ENTRY|[18]|Limit.getDmlStatements() 17:14:58.208 (208328115)|SYSTEM_METHOD_EXIT|[18]|Limit.getDmlStatements() 17:14:58.208 (208360341)|SYSTEM_METHOD_ENTRY|[18]|String.valueOf(Object) 17:14:58.208 (208379606)|SYSTEM_METHOD_EXIT|[18]|String.valueOf(Object) 17:14:58.208 (208390294)|SYSTEM_METHOD_ENTRY|[18]|Limit.getLimitDmlStatements() 17:14:58.208 (208401225)|SYSTEM_METHOD_EXIT|[18]|Limit.getLimitDmlStatements() 17:14:58.208 (208417086)|SYSTEM_METHOD_ENTRY|[18]|String.valueOf(Object) 17:14:58.208 (208433053)|SYSTEM_METHOD_EXIT|[18]|String.valueOf(Object) 17:14:58.208 (208448370)|SYSTEM_METHOD_ENTRY|[18]|System.debug(ANY) 17:14:58.208 (208455254)|USER_DEBUG|[18]|DEBUG|<b>Enter in testData12::0::150</b> 17:14:58.208 (208460659)|SYSTEM_METHOD_EXIT|[18]|System.debug(ANY) 17:14:58.208 (208476092)|SYSTEM_METHOD_ENTRY|[19]|system.Test.stopTest() 17:14:58.210 (210157421)|SYSTEM_METHOD_EXIT|[19]|system.Test.stopTest() 17:14:58.200 (210186511)|CUMULATIVE_LIMIT_USAGE 17:14:58.200|LIMIT_USAGE_FOR_NS|(default)| Number of SOQL queries: 0 out of 100 Number of query rows: 0 out of 50000 Number of SOSL queries: 0 out of 20 Number of DML statements: 1 out of 150 Number of DML rows: 1 out of 10000 Maximum CPU time: 0 out of 10000 Maximum heap size: 0 out of 6000000 Number of callouts: 0 out of 100 Number of Email Invocations: 0 out of 10 Number of future calls: 0 out of 50 Number of queueable jobs added to the queue: 0 out of 50 Number of Mobile Apex push calls: 0 out of 10 17:14:58.200|TESTING_LIMITS 17:14:58.200|LIMIT_USAGE_FOR_NS|(default)| Number of SOQL queries: 1 out of 100 Number of query rows: 1 out of 50000 Number of SOSL queries: 0 out of 20 Number of DML statements: 0 out of 150 Number of DML rows: 0 out of 10000 Maximum CPU time: 0 out of 10000 Maximum heap size: 0 out of 6000000 Number of callouts: 0 out of 100 Number of Email Invocations: 0 out of 10 Number of future calls: 0 out of 50 Number of queueable jobs added to the queue: 0 out of 50 Number of Mobile Apex push calls: 0 out of 10 17:14:58.200|CUMULATIVE_LIMIT_USAGE_END 17:14:58.210 (210235275)|CODE_UNIT_FINISHED|myTest.testData1 17:14:58.211 (211251838)|EXECUTION_FINISHED 17:14:58.260 (260437301)|EXECUTION_STARTED 17:14:58.260 (260456749)|CODE_UNIT_STARTED|[EXTERNAL]|01pB0000000HolG|myTest.testData2 17:14:58.260 (260792341)|METHOD_ENTRY|[2]|01pB0000000HolG|myTest.myTest() 17:14:58.260 (260803454)|METHOD_EXIT|[2]|myTest 17:14:58.260 (260915130)|SYSTEM_METHOD_ENTRY|[24]|Limit.getDmlStatements() 17:14:58.260 (260967160)|SYSTEM_METHOD_EXIT|[24]|Limit.getDmlStatements() 17:14:58.261 (261006042)|SYSTEM_METHOD_ENTRY|[24]|String.valueOf(Object) 17:14:58.261 (261028543)|SYSTEM_METHOD_EXIT|[24]|String.valueOf(Object) 17:14:58.261 (261043955)|SYSTEM_METHOD_ENTRY|[24]|Limit.getLimitDmlStatements() 17:14:58.261 (261058175)|SYSTEM_METHOD_EXIT|[24]|Limit.getLimitDmlStatements() 17:14:58.261 (261074889)|SYSTEM_METHOD_ENTRY|[24]|String.valueOf(Object) 17:14:58.261 (261091042)|SYSTEM_METHOD_EXIT|[24]|String.valueOf(Object) 17:14:58.261 (261113424)|SYSTEM_METHOD_ENTRY|[24]|System.debug(ANY) 17:14:58.261 (261122513)|USER_DEBUG|[24]|DEBUG|<b>Enter in testData2::1::150</b><b> </b>17:14:58.261 (261128396)|SYSTEM_METHOD_EXIT|[24]|System.debug(ANY) 17:14:58.261 (261325197)|SOQL_EXECUTE_BEGIN|[25]|Aggregations:0|SELECT Name FROM Account 17:14:58.264 (264020860)|SOQL_EXECUTE_END|[25]|Rows:1 17:14:58.264 (264157839)|SYSTEM_METHOD_ENTRY|[26]|System.assertEquals(ANY, ANY) 17:14:58.264 (264206417)|SYSTEM_METHOD_EXIT|[26]|System.assertEquals(ANY, ANY) 17:14:58.264 (264221077)|SYSTEM_METHOD_ENTRY|[27]|Limit.getDmlStatements() 17:14:58.264 (264249128)|SYSTEM_METHOD_EXIT|[27]|Limit.getDmlStatements() 17:14:58.264 (264276258)|SYSTEM_METHOD_ENTRY|[27]|String.valueOf(Object) 17:14:58.264 (264294737)|SYSTEM_METHOD_EXIT|[27]|String.valueOf(Object) 17:14:58.264 (264306009)|SYSTEM_METHOD_ENTRY|[27]|Limit.getLimitDmlStatements() 17:14:58.264 (264316703)|SYSTEM_METHOD_EXIT|[27]|Limit.getLimitDmlStatements() 17:14:58.264 (264332518)|SYSTEM_METHOD_ENTRY|[27]|String.valueOf(Object) 17:14:58.264 (264348607)|SYSTEM_METHOD_EXIT|[27]|String.valueOf(Object) 17:14:58.264 (264363269)|SYSTEM_METHOD_ENTRY|[27]|System.debug(ANY) 17:14:58.264 (264369412)|USER_DEBUG|[27]|DEBUG|<b>Enter in testData22::1::150</b> 17:14:58.264 (264374741)|SYSTEM_METHOD_EXIT|[27]|System.debug(ANY) 17:14:58.254 (264399759)|CUMULATIVE_LIMIT_USAGE 17:14:58.254|LIMIT_USAGE_FOR_NS|(default)| Number of SOQL queries: 1 out of 100 Number of query rows: 1 out of 50000 Number of SOSL queries: 0 out of 20 Number of DML statements: 1 out of 150 Number of DML rows: 1 out of 10000 Maximum CPU time: 0 out of 10000 Maximum heap size: 0 out of 6000000 Number of callouts: 0 out of 100 Number of Email Invocations: 0 out of 10 Number of future calls: 0 out of 50 Number of queueable jobs added to the queue: 0 out of 50 Number of Mobile Apex push calls: 0 out of 10 17:14:58.254|CUMULATIVE_LIMIT_USAGE_END 17:14:58.264 (264433109)|CODE_UNIT_FINISHED|myTest.testData2 17:14:58.265 (265477515)|EXECUTION_FINISHED
Quiere decir, que está parte del código donde declaramos el @testSetup es manejado como un bloque estático en la clase, lo cuál hará que todas las variables tengan una sola instancia, es correcto esto ?
Hola Jefferson,
Gracias por tu seguimiento y por tu pregunta.
Podríamos decir que se trata como un bloque estático ( de hecho tiene esa notación) Sin embargo no podemos acceder a las variables el método directamente, como por ejemplo en este caso newAccount que debemos hacer una consulta a base de datos para poder recuperarla.
Ahora, aquí está la gracia de este método, si se modificase el registro de tipo Account (newAccount) , por ejemplo cambiar el nombre esto solamente tendría efecto en el contexto del método test que se esta ejecutando en ese momento. Todos los otros métodos test no se verían afectados por el cambio realizado al registro en un determinado método.
Un pequeño ejemplo:
@testSetup
static void createData()
{
Account newAccount = new Account(Name='Account1');
insert newAccount;
}
static testMethod void testData1()
{
System.debug(‘Entra en testData1’);
Account newAccount = [Select Name From Account];
newAccount.Name = ‘patata’;
update newAccount;
System.assertEquals('patata', newAccount.Name);
}
static testMethod void testData2()
{
System.debug(‘Entra en testData2’);
Account newAccount = [Select Name From Account];
// tras ejecutarse el metodo anterior todo se restaura a los valores originales con los que se hizo la carga de datos
System.assertEquals('Account1', newAccount.Name);
}
Espero haber aclarado la duda, muchas gracias de nuevo!
Muy buen post Cristina, además me parece un añadido bastante útil para, como comentas, simplificar y clarificar código y poder reutilizar registros.
Pero tengo una duda que no se si se ha aclarado ya en otra entrada, ¿si tu creas la clase con seeAllData=true, puedes seguir usando esta nueva anotación?
Un saludo!
Hola Javi,
Gracias por el seguimiento y la pregunta. Y como hemos hablado no te preocupes por lo de Cristina ya me ha pasado en otras ocasiones 😛 .. pero que no vuelva a ocurrir!! Jejeje.
Muy buena pregunta, hay varias consideraciones a tener en cuenta:
1.- Cuando se usa sellAllData=true no se pueden tener métodos @testSetup. Solamente están permitidos cuando los test están aislados de los datos reales de la org.
2.- Cuando un método @testSetup falla, por una excepción DML por ejemplo, la clase entera falla, no se ejecutan los siguientes métodos test.
3.- Cuando un método @testSetup llama a otro método que no es de tipo test, no se calcula la cobertura de método que no es test.
Espero haber aclarado la duda 🙂
Hasta pronto!
Si Carolina! 🙂 Jeje Me responde perfectamente. Me llamaba la atención que estuviera permitido usarse con datos reales, por lo que este control lo veo correcto para evitar problemas posteriores en los Unit Tests.
Un saludo!
Gracias Javi!! 🙂