Información general sobre pruebas de unidad de Apex
Objetivos de aprendizaje
Después de completar esta unidad, podrá:
- Describir las ventajas clave de las pruebas de unidad de Apex.
- Definir una clase con métodos de prueba.
- Ejecutar todos los métodos de prueba en una clase e inspeccionar los errores.
- Crear y ejecutar un conjunto de clases de prueba.
Pruebas de unidad de Apex
El marco de pruebas de Apex permite escribir código y ejecutar pruebas para clases y desencadenadores de Apex en la Plataforma Lightning. Las pruebas de unidad de Apex le permiten garantizar la alta calidad de su código Apex y cumplir los requisitos para la implementación de Apex.
Las pruebas son la clave para el desarrollo correcto a largo plazo y un componente decisivo del proceso de desarrollo. El marco de pruebas de Apex facilita la prueba del código Apex. El código Apex solamente se puede escribir en un entorno de sandbox o una organización de desarrollador, pero no de producción. El código Apex se puede implementar en una organización de producción desde un sandbox. Además, los desarrolladores de aplicaciones pueden distribuir el código Apex entre los clientes desde sus organizaciones de desarrollador mediante la carga de paquetes a AppExchange deLightning Platform. Además de ser esenciales para garantizar la calidad, las pruebas de unidad de Apex son además requisitos para la implementación y distribución de Apex.
Estos son los beneficios de las pruebas de unidad de Apex.
- Garantizar que las clases y los desencadenadores de Apex funcionen según lo esperado.
- Disponer de un conjunto de pruebas de regresión que se puedan volver a ejecutar cada vez que se actualicen las clases y los desencadenadores para garantizar que las actualizaciones futuras que realice en la aplicación no afecten a la funcionalidad existente.
- Cumplir los requisitos de cobertura de código para la implementación de Apex para producción o la distribución de Apex a los clientes mediante paquetes.
- Entrega de aplicaciones de alta calidad a la organización de producción, lo que aumenta la productividad de los usuarios de producción.
- Entrega de aplicaciones de alta calidad a suscriptores de paquetes, lo que aumenta la confianza de los clientes.
Requisito de cobertura de código para la implementación
Para poder implementar su código o paquete para AppExchange de Lightning Platform, el 75 % del código Apex como mínimo debe estar cubierto por pruebas y todas deben haber sido aprobadas. Además, cada desencadenador debe tener determinada cobertura. Aunque la cobertura de código sea un requisito para la implementación, no escriba pruebas solamente para cumplir este requisito. Asegúrese de probar casos de uso en su aplicación, lo que incluye casos de pruebas positivas y negativas, y el procesamiento masivo y de un solo registro.
Sintaxis de métodos de prueba
Los métodos de prueba se definen mediante la anotación @isTest
y presentan la siguiente sintaxis:
@isTest static void testName() { // code_block }
La anotación @isTest
lleva varios modificadores entre paréntesis y separados por espacios en blanco. Describiremos uno de estos parámetros más adelante.
Dado que la visibilidad de un método no es importante, la declaración de un método de prueba como público o privado no supone ninguna diferencia, ya que el marco de pruebas siempre puede acceder a los métodos de prueba. Por este motivo, los modificadores de acceso se omiten en la sintaxis.
Los métodos de prueba se deben definir en clases de prueba, las cuales son clases anotadas con @isTest
. En esta clase de ejemplo se muestra una definición de una clase de prueba con un solo método de prueba.
@isTest private class MyTestClass { @isTest static void myTest() { // code_block } }
Las clases de prueba pueden ser privadas o públicas. Si va a usar una clase de prueba para pruebas de unidad únicamente, declárela como privada. Las clases de prueba públicas se suelen usar para clases de fábrica de datos de prueba, lo cual se describe más adelante.
Ejemplo de prueba de unidad: Probar la clase TemperatureConverter
El siguiente ejemplo sencillo es una clase de prueba con tres métodos de prueba. El método de clase que se prueba obtiene la temperatura en grados Fahrenheit como una entrada. Convierte este valor de temperatura en grados Celsius y devuelve el resultado convertido. Vamos a agregar la clase personalizada y su clase de prueba.
- En Developer Console, haga clic en File (Archivo) | New (Nuevo) | Apex Class (Clase de Apex) e ingrese
TemperatureConverter
para el nombre de clase y, a continuación, haga clic en OK (Aceptar).
- Sustituya el cuerpo de clase predeterminado por el siguiente.
public class TemperatureConverter { // Takes a Fahrenheit temperature and returns the Celsius equivalent. public static Decimal FahrenheitToCelsius(Decimal fh) { Decimal cs = (fh - 32) * 5/9; return cs.setScale(2); } }
- Pulse Ctrl+S para guardar la clase.
- Repita los pasos anteriores para crear la clase
TemperatureConverterTest
. Agregue lo siguiente para esta clase.@isTest private class TemperatureConverterTest { @isTest static void testWarmTemp() { Decimal celsius = TemperatureConverter.FahrenheitToCelsius(70); System.assertEquals(21.11,celsius); } @isTest static void testFreezingPoint() { Decimal celsius = TemperatureConverter.FahrenheitToCelsius(32); System.assertEquals(0,celsius); } @isTest static void testBoilingPoint() { Decimal celsius = TemperatureConverter.FahrenheitToCelsius(212); System.assertEquals(100,celsius,'Boiling point temperature is not expected.'); } @isTest static void testNegativeTemp() { Decimal celsius = TemperatureConverter.FahrenheitToCelsius(-10); System.assertEquals(-23.33,celsius); } }
La clase de prueba TemperatureConverterTest
verifica si el método funciona según lo esperado mediante la llamada a dicho método con distintas entradas para la temperatura en grados Fahrenheit. Cada método de prueba verifica un solo tipo de entrada: temperatura alta, punto de congelación, punto de ebullición y valor de temperatura negativo. Las verificaciones se realizan mediante la llamada al método System.assertEquals()
y se aplican dos parámetros: el primero es el valor esperado y el segundo es el valor real. Hay otra versión de este método en la que se aplica un tercer parámetro, que es una cadena que describe la comparación realizada, la cual se usa en testBoilingPoint()
. Esta cadena opcional se registra si se produce un error de afirmación.
Vamos a ejecutar los métodos de esta clase.
- En Developer Console, haga clic en Prueba | Nueva ejecución.
- En Clases de prueba, haga clic en TemperatureConverterTest.
- Si desea agregar todos los métodos de prueba de la clase
TemperatureConverterTest
para la ejecución de la prueba, haga clic en Add Selected (Agregar selección).
- Haga clic en Ejecutar.
- En la ficha Tests (Pruebas), puede ver el estado de las pruebas a medida que se ejecutan. Amplíe la ejecución de pruebas y vuelva a ampliarla hasta poder ver la lista de pruebas individuales ejecutadas. Todas estas pruebas incluyen marcas de verificación verdes.
Una vez ejecutadas las pruebas, la cobertura de código se genera automáticamente para las clases y los desencadenadores de Apex de la organización. Puede comprobar el porcentaje de cobertura de código en la ficha Tests (Pruebas) de la consola de desarrollador. En este ejemplo, la clase probada (clase TemperatureConverter
) tiene una cobertura del 100%, como se muestra en la imagen.
Aunque un solo método de prueba puede tener como resultado la cobertura completa de la clase TemperatureConverter
, es importante probar con distintas entradas para garantizar la calidad del código. Obviamente, no es posible verificar cada punto de datos, pero puede probar puntos de datos comunes y distintos intervalos de entrada. Por ejemplo, puede verificar el paso de números positivos y negativos, valores de límite y valores de parámetros no válidos para confirmar un comportamiento negativo. Las pruebas para la clase TemperatureConverter
permiten verificar puntos de datos comunes, como el punto de ebullición y los valores de temperatura negativos.
La clase de prueba TemperatureConverterTest
no cubre las entradas no válidas ni las condiciones de límite. Las condiciones de límite están relacionadas con los valores mínimos y máximos. En este caso, el método de conversión de temperatura acepta un Decimal
, lo que permite el uso de números altos y superiores a los valores Double
(Dobles). En el caso de las entradas no válidas, no existe ningún valor de temperatura no válido, sino que la única entrada no válida es null. ¿Cómo controla el método de conversión este valor? En este caso, cuando el tiempo de ejecución de Apex elimina la referencia a la variable de parámetro para evaluar la fórmula, genera System.NullPointerException
. Puede modificar el método FahrenheitToCelsius()
para buscar una entrada no válida, devolver null si ese es el caso y, a continuación, agregar una prueba para verificar el comportamiento de la entrada no válida.
En este punto, todas las pruebas se aprueban dado que la fórmula de conversión usada en el método de clase es correcta. Sin embargo, este es un proceso aburrido. Vamos a simular un error solamente para ver qué sucede cuando una afirmación genera un error. Por ejemplo, vamos a modificar la prueba de punto de ebullición y a pasar un valor esperado falso para el punto de ebullición en grados Celsius (0 en lugar de 100). Esto genera un error del método de prueba correspondiente.
- Cambie el método de prueba
testBoilingPoint()
por lo siguiente:@isTest static void testBoilingPoint() { Decimal celsius = TemperatureConverter.FahrenheitToCelsius(212); // Simulate failure System.assertEquals(0,celsius,'Boiling point temperature is not expected.'); }
- Para ejecutar la misma ejecución de prueba, haga clic en la última ejecución en la ficha Tests (Pruebas) y, a continuación, en Test (Prueba) | Rerun (Volver a ejecutar). La afirmación de
testBoilingPoint()
no surte efecto y genera un error grave (AssertException
que no se puede capturar).
- Para comprobar los resultados de la ficha Tests (Pruebas), expanda la última prueba ejecutada. La ejecución de pruebas indica una de cuatro pruebas con errores. Para obtener más información sobre el error, haga doble clic en la prueba ejecutada. Los resultados detallados se muestran en una ficha independiente, como se puede ver en esta imagen.
[Texto alternativo: Inspeccionar resultados de una prueba con errores en Developer Console]
- Para ver el mensaje de error de esta prueba incorrecta, haga doble clic en la columna de errores de dicha prueba. Verá lo siguiente: el texto descriptivo junto a
Assertion Failed:
(La afirmación ha fallado) es el texto que incluimos en la declaraciónSystem.assertEquals()
.System.AssertException:Assertion Failed:Boiling point temperature is not expected.:Expected:0, Actual:100.00
(La temperatura del punto de ebullición no es la esperada.:Esperada:0, Real:100.00).
Los datos de estos métodos de prueba son números y no registros de Salesforce. Encontrará más información sobre cómo probar los registros de Salesforce y configurar los datos en la siguiente unidad.
Aumentar la cobertura de código
Al escribir pruebas, intente alcanzar la máxima cobertura de código posible. Evite alcanzar una cobertura de tan solo el 75%, ya que esta es la cobertura mínima que requiere Plataforma Lightning para las implementaciones y los paquetes. Cuantos más casos de prueba cubren las pruebas, mayor es la probabilidad de que el código sea consistente. En ocasiones, incluso después de escribir métodos de prueba para todos los métodos de clase, la cobertura de código no es del 100%. Una causa común es que no se cubren todos los valores de datos para la ejecución de código condicional. Por ejemplo, algunos valores de datos tienden a ser ignorados si el método de clase tiene declaraciones if que producen distintas ramas para su ejecución en función de si se cumple la condición evaluada. Asegúrese de que los métodos de prueba representan estos valores distintos.
En este ejemplo se incluye el método de clase getTaskPriority()
, el cual contiene dos declaraciones if
. La tarea principal de este método es devolver un valor de cadena de prioridad basado en el estado de un prospecto determinado. El método valida el estado primero y devuelve null si el estado no es válido. Si el estado es CA, el método devuelve 'High'. En caso contrario, devuelve 'Normal' para cualquier otro valor de estado.
public class TaskUtil { public static String getTaskPriority(String leadState) { // Validate input if(String.isBlank(leadState) || leadState.length() > 2) { return null; } String taskPriority; if(leadState == 'CA') { taskPriority = 'High'; } else { taskPriority = 'Normal'; } return taskPriority; } }
Esta es la clase de prueba para el método getTaskPriority()
. El método de prueba simplemente llama a getTaskPriority()
con un solo estado (“NY”).
@isTest private class TaskUtilTest { @isTest static void testTaskPriority() { String pri = TaskUtil.getTaskPriority('NY'); System.assertEquals('Normal', pri); } }
Vamos a ejecutar esta clase de prueba (TaskUtilTest
) en Developer Console y a comprobar la cobertura de código para la clase TaskUtil
correspondiente que cubre esta prueba. Una vez ejecutada la prueba, la cobertura de código para TaskUtil
se indica como un 75%. Si abre esta clase en la consola de desarrollador, verá seis líneas azules (cubiertas) y dos líneas rojas (no cubiertas), como se muestra en esta imagen.
El motivo por el que la línea 5 no se ha cubierto es que nuestra clase de prueba no contenía ninguna prueba para pasar un parámetro de estado no válido. De forma similar, la línea 11 no se abarcó porque el método de prueba no pasó “CA” como estado. Vamos a agregar dos métodos de prueba para cubrir estos casos. A continuación se muestra la clase de prueba completa después de agregar los métodos de prueba testTaskHighPriority()
y testTaskPriorityInvalid()
. Si vuelve a ejecutar esta clase de prueba con Ejecutar todo o Nueva ejecución, la cobertura de código para TaskUtil
será del 100 %.
@isTest private class TaskUtilTest { @isTest static void testTaskPriority() { String pri = TaskUtil.getTaskPriority('NY'); System.assertEquals('Normal', pri); } @isTest static void testTaskHighPriority() { String pri = TaskUtil.getTaskPriority('CA'); System.assertEquals('High', pri); } @isTest static void testTaskPriorityInvalid() { String pri = TaskUtil.getTaskPriority('Montana'); System.assertEquals(null, pri); } }
Crear y ejecutar un conjunto de pruebas
Un conjunto de pruebas es una recopilación de clases de prueba de Apex que se ejecutan conjuntamente. Por ejemplo, cree un conjunto de pruebas que ejecute cada vez que prepare una implementación o que Salesforce lance una nueva versión. Configure un conjunto de pruebas en la consola de desarrollador para definir un conjunto de clases de prueba que pueda ejecutar conjuntamente de forma regular.
Ahora tiene dos clases de prueba en su organización. Estas dos clases no están relacionadas, pero vamos a suponer de momento que sí lo están. Suponga que hay casos en los que desea ejecutar estas dos clases de prueba, pero no desea ejecutar todas las pruebas de la organización. Cree un conjunto de pruebas que contenga ambas clases y, a continuación, ejecute las pruebas del conjunto.
- En Developer Console, seleccione Prueba | Nuevo conjunto.
- Ingrese
TempConverterTaskUtilSuite
como nombre del conjunto y, a continuación, haga clic en OK (Aceptar).
- Seleccione TaskUtilTest, mantenga pulsada la tecla Ctrl y seleccione TemperatureConverterTest.
- Para agregar las clases seleccionadas al conjunto, haga clic en >.
- Haga clic en Guardar.
- Seleccione Prueba | Nueva ejecución de conjunto.
- Seleccione TempConverterTaskUtilSuite y, a continuación, haga clic en > para mover
TempConverterTaskUtilSuite
a la columna Selected Test Suites (Conjuntos de prueba seleccionados).
- Haga clic en Run Suites (Ejecutar conjuntos).
- En la ficha Tests (Pruebas), puede controlar el estado de las pruebas a medida que se ejecutan. Amplíe la ejecución de pruebas y vuelva a ampliarla hasta poder ver la lista de pruebas individuales ejecutadas. Al igual que en el caso de una ejecución de métodos de prueba individuales, puede hacer doble clic en los nombres de los métodos para ver los resultados detallados de las pruebas.
Crear datos de prueba
Los registros de Salesforce creados en métodos de prueba no se confirman para la base de datos. Estos se revierten una vez que finaliza la ejecución de la prueba. Este comportamiento de reversión es de utilidad para las pruebas porque no necesita limpiar los datos de prueba después de ejecutar la prueba.
De forma predeterminada, las pruebas de Apex no tienen acceso a los datos preexistentes de la organización, a excepción del acceso a objetos de configuración y metadatos, como los objetos de usuario o perfil. Configure los datos de prueba para las pruebas. La creación de datos de prueba aumenta la consistencia de las pruebas y permite evitar errores generados por la ausencia o el cambio de los datos de la organización. Puede crear datos de prueba directamente en el método de prueba o mediante una clase de prueba de utilidad, como verá más adelante.
Más información
- Puede usar la extensión de Apex de Salesforce para Visual Studio Code a fin de ejecutar pruebas de Apex y verificar la funcionalidad de su código.
- Puede ahorrar hasta 6 MB de código Apex en cada organización. Las clases de prueba anotadas con
@isTest
no cuentan para este límite.
- Aunque los datos de prueba se revierten, no se usa ninguna base de datos independiente para las pruebas. Por lo tanto, en el caso de determinados sObjects que tienen campos con restricciones de exclusividad, la inserción de registros de sObject duplicados genera un error.
- Los métodos de prueba no permiten el envío de emails.
- Los métodos de prueba no pueden hacer llamadas a servicios externos. Puede usar llamadas ficticias en las pruebas.
- Las búsquedas SOSL realizadas en una prueba devuelven resultados vacíos. A fin de garantizar los resultados esperados, use
Test.setFixedSearchResults()
para definir los registros que va a devolver la búsqueda.
Recursos
-
Guía del desarrollador de Apex: Mejores prácticas sobre las pruebas
-
Guía del desarrollador de Apex: ¿Qué son las pruebas de unidades de Apex?
-
Guía del desarrollador de Apex: Aislamiento de los datos de prueba desde los datos de organización en las pruebas de unidad
-
Ayuda de Salesforce: Comprobación de la cobertura del código
Preparación para el reto práctico
Para completar el desafío práctico de esta unidad, deberá crear una nueva clase de Appex denominada VerifyDate
con el siguiente código:
public class VerifyDate { //method to handle potential checks against two dates public static Date CheckDates(Date date1, Date date2) { //if date2 is within the next 30 days of date1, use date2. Otherwise use the end of the month if(DateWithin30Days(date1,date2)) { return date2; } else { return SetEndOfMonthDate(date1); } } //method to check if date2 is within the next 30 days of date1 private static Boolean DateWithin30Days(Date date1, Date date2) { //check for date2 being in the past if( date2 < date1) { return false; } //check that date2 is within (>=) 30 days of date1 Date date30Days = date1.addDays(30); //create a date 30 days away from date1 if( date2 >= date30Days ) { return false; } else { return true; } } //method to return the end of the month of a given date private static Date SetEndOfMonthDate(Date date1) { Integer totalDays = Date.daysInMonth(date1.year(), date1.month()); Date lastDay = Date.newInstance(date1.year(), date1.month(), totalDays); return lastDay; } }