Pruebas unitarias unit-testing
Este tutorial cubre la implementación de una prueba unitaria que valida el comportamiento del modelo Sling del componente Byline, creado en el tutorial Componente personalizado.
Requisitos previos prerequisites
Revise las herramientas y las instrucciones necesarias para configurar un entorno de desarrollo local.
Si Java™ 8 y Java™ 11 están instalados en el sistema, el ejecutor de pruebas de código VS puede elegir el tiempo de ejecución de Java™ inferior al ejecutar las pruebas, lo que da como resultado errores de prueba. Si esto ocurre, desinstale Java™ 8.
Proyecto de inicio
Consulte el código de línea de base en el que se basa el tutorial:
-
Consulte la rama
tutorial/unit-testing-start
de GitHubcode language-shell $ cd aem-guides-wknd $ git checkout tutorial/unit-testing-start
-
AEM Implemente una base de código en una instancia de local con sus habilidades con Maven:
code language-shell $ mvn clean install -PautoInstallSinglePackage
note note NOTE AEM Si utiliza la versión 6.5 o 6.4 de la aplicación, anexe el perfil classic
a cualquier comando de Maven.code language-shell $ mvn clean install -PautoInstallSinglePackage -Pclassic
Siempre puede ver el código terminado en GitHub o desprotegerlo localmente cambiando a la rama tutorial/unit-testing-start
.
Objetivo
- Comprender los conceptos básicos de las pruebas unitarias.
- AEM Obtenga información sobre los marcos de trabajo y las herramientas que se utilizan normalmente para probar el código de.
- AEM Comprender las opciones para burlarse o simular recursos de la unidad al escribir pruebas de unidad.
Fondo unit-testing-background
AEM En este tutorial, exploraremos cómo escribir Pruebas unitarias para el Modelo Sling de nuestro componente Byline (creado en Creación de un componente de la unidad personalizado). Las pruebas unitarias son pruebas en tiempo de compilación escritas en Java™ que verifican el comportamiento esperado del código Java™. Cada prueba unitaria suele ser pequeña y valida el resultado de un método (o unidades de trabajo) con los resultados esperados.
AEM Utilizamos las prácticas recomendadas de la y utilizamos:
- JUnit 5
- Marco de prueba Mockito
- wcm.io Test Framework (que se basa en Apache Sling Mocks)
Pruebas unitarias y Cloud Manager de Adobe unit-testing-and-adobe-cloud-manager
Cloud Manager AEM de Adobe integra la ejecución de pruebas unitarias y la creación de informes de cobertura de código en su canalización de CD/CI para ayudar a alentar y promocionar las prácticas recomendadas del código de prueba de unidades.
Aunque el código de prueba unitaria es una buena práctica para cualquier base de código, al utilizar Cloud Manager es importante aprovechar sus funciones de prueba de calidad de código y generación de informes al proporcionar pruebas unitarias para que Cloud Manager se ejecute.
Actualizar las dependencias Maven de prueba inspect-the-test-maven-dependencies
El primer paso es inspeccionar las dependencias de Maven para que admitan la escritura y ejecución de las pruebas. Se requieren cuatro dependencias:
- JUnit5
- Marco de prueba de Mockito
- Apache Sling se burla
- AEM Marco de prueba de Mocks (por io.wcm)
AEM AEM Las dependencias de prueba JUnit5, Mockito y Mocks** se agregan automáticamente al proyecto durante la configuración mediante el arquetipo Maven de tipo de archivo.
-
AEM Para ver estas dependencias, abra el POM del reactor principal en aem-guides-wknd/pom.xml, vaya a
<dependencies>..</dependencies>
y vea las dependencias de las pruebas JUnit, Mockito, Apache Sling Mocks y Mock de las pruebas de io.wcm en<!-- Testing -->
. -
Asegúrese de que
io.wcm.testing.aem-mock.junit5
está establecido en 4.1.0:code language-xml <dependency> <groupId>io.wcm</groupId> <artifactId>io.wcm.testing.aem-mock.junit5</artifactId> <version>4.1.0</version> <scope>test</scope> </dependency>
note caution CAUTION El tipo de archivo 35 genera el proyecto con io.wcm.testing.aem-mock.junit5
versión 4.1.8. Cambie a 4.1.0 para seguir con el resto de este capítulo. -
Abra aem-guides-wknd/core/pom.xml y vea que las dependencias de prueba correspondientes están disponibles.
Una carpeta de origen paralela en el proyecto core contendrá las pruebas unitarias y cualquier archivo de prueba auxiliar. Esta carpeta test proporciona separación de las clases de prueba del código fuente, pero permite que las pruebas actúen como si vivieran en los mismos paquetes que el código fuente.
Creación de la prueba JUnit creating-the-junit-test
Las pruebas unitarias suelen asignar clases de 1 a 1 con Java™. En este capítulo, escribiremos una prueba JUnit para BylineImpl.java, que es el modelo Sling que respalda el componente Byline.
Ubicación donde se almacenan las pruebas unitarias.
-
Cree una prueba unitaria para
BylineImpl.java
creando una nueva clase Java™ ensrc/test/java
en una estructura de carpetas de paquetes Java™ que refleje la ubicación de la clase Java™ que se va a probar.Ya que estamos probando
src/main/java/com/adobe/aem/guides/wknd/core/models/impl/BylineImpl.java
cree una clase Java™ de prueba unitaria correspondiente en
src/test/java/com/adobe/aem/guides/wknd/core/models/impl/BylineImplTest.java
El sufijo
Test
del archivo de prueba unitaria,BylineImplTest.java
, es una convención que nos permite- Identifíquelo fácilmente como el archivo de prueba para
BylineImpl.java
- Pero también, diferencie el archivo de prueba de la clase que se está probando,
BylineImpl.java
Revisión de BylineImplTest.java reviewing-bylineimpltest-java
En este punto, el archivo de prueba JUnit es una clase Java™ vacía.
-
Actualice el archivo con el siguiente código:
code language-java package com.adobe.aem.guides.wknd.core.models.impl; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class BylineImplTest { @BeforeEach void setUp() throws Exception { } @Test void testGetName() { fail("Not yet implemented"); } @Test void testGetOccupations() { fail("Not yet implemented"); } @Test void testIsEmpty() { fail("Not yet implemented"); } }
-
El primer método
public void setUp() { .. }
está anotado con@BeforeEach
de JUnit, que indica al ejecutor de pruebas de JUnit que ejecute este método antes de ejecutar cada método de prueba en esta clase. Esto proporciona un lugar práctico para inicializar el estado de prueba común requerido por todas las pruebas. -
Los métodos siguientes son los métodos de prueba, cuyos nombres llevan el prefijo
test
por convención y están marcados con la anotación@Test
. Tenga en cuenta que, de forma predeterminada, todas nuestras pruebas están configuradas para fallar, ya que aún no las hemos implementado.Para empezar, comenzamos con un único método de prueba para cada método público en la clase que estamos probando, así que:
table 0-row-3 1-row-3 2-row-3 3-row-3 BylineImpl.java BylineImplTest.java getName() está probado por testGetName() getOccupations() está probado por testGetOccupations() isEmpty() está probado por testIsEmpty() Estos métodos se pueden ampliar según sea necesario, como veremos más adelante en este capítulo.
Cuando se ejecuta esta clase de prueba JUnit (también conocida como caso de prueba JUnit), cada método marcado con
@Test
se ejecutará como una prueba que puede aprobar o no.
core/src/test/java/com/adobe/aem/guides/wknd/core/models/impl/BylineImplTest.java
-
Ejecute el caso de prueba JUnit haciendo clic con el botón derecho en el archivo
BylineImplTest.java
y pulsando Ejecutar.
Como se esperaba, todas las pruebas fallan, ya que aún no se han implementado.Haga clic con el botón derecho en BylineImplTests.java > Ejecutar
Revisión de BylineImpl.java reviewing-bylineimpl-java
Al escribir pruebas unitarias, existen dos enfoques principales:
- Desarrollo controlado por pruebas o TDD, que implica escribir las pruebas unitarias de forma incremental, inmediatamente antes de que se desarrolle la implementación; escriba una prueba y escriba la implementación para que la prueba se apruebe.
- Implementación: primero desarrollo, que implica desarrollar primero el código de trabajo y, a continuación, escribir pruebas que validen dicho código.
En este tutorial, se usa el método más reciente (ya que hemos creado un BylineImpl.java en funcionamiento en un capítulo anterior). Debido a esto, debemos revisar y comprender los comportamientos de sus métodos públicos, pero también algunos de sus detalles de implementación. AEM Esto puede sonar contrario, ya que una buena prueba solo debe preocuparse por las entradas y salidas, sin embargo, cuando se trabaja en el área de la implementación, hay varias consideraciones de implementación que deben entenderse para construir pruebas de trabajo.
AEM AEM AEM AEM La TDD en el contexto de la requiere un nivel de experiencia y la mejor manera de adoptarla es a través de desarrolladores de competentes en el desarrollo y prueba de unidades de código de la.
AEM Configuración del contexto de prueba de setting-up-aem-test-context
AEM AEM AEM La mayoría del código escrito para la se basa en las API de JCR, Sling o, que a su vez requieren el contexto de una aplicación en ejecución para que se ejecute correctamente.
AEM Dado que las pruebas unitarias se ejecutan durante la compilación, no existe ese contexto fuera del contexto de una instancia de ejecución de la. AEM AEM Para facilitarle este proceso, wcm.io's Mocks crea un contexto ficticio que permite que estas API en su mayoría actúen como si se estuvieran ejecutando en el espacio de trabajo de la red de la red de distribución de datos (API) de la red de datos .
-
AEM Cree un contexto de usando wcm.io
AemContext
en BylineImplTest.java agregándolo como una extensión JUnit decorada con@ExtendWith
al archivo BylineImplTest.java. La extensión se encarga de todas las tareas de inicialización y limpieza necesarias. Cree una variable de clase paraAemContext
que se pueda usar para todos los métodos de prueba.code language-java import org.junit.jupiter.api.extension.ExtendWith; import io.wcm.testing.mock.aem.junit5.AemContext; import io.wcm.testing.mock.aem.junit5.AemContextExtension; ... @ExtendWith(AemContextExtension.class) class BylineImplTest { private final AemContext ctx = new AemContext();
AEM AEM Esta variable,
ctx
, expone un contexto de ficticio que proporciona algunas abstracciones de Sling y de la versión en inglés:- El modelo Sling BylineImpl está registrado en este contexto
- Las estructuras de contenido JCR simuladas se crean en este contexto
- Los servicios OSGi personalizados se pueden registrar en este contexto
- AEM Proporciona varios objetos de prueba y ayudantes comunes necesarios, como objetos SlingHttpServletRequest, varios servicios de Sling y OSGi de prueba, como ModelFactory, PageManager, Page, Template, ComponentManager, Component, TagManager, Tag, etc.
- No se han implementado todos los métodos para estos objetos.
- ¡Y mucho más!
El objeto
ctx
actuará como punto de entrada para la mayor parte de nuestro contexto ficticio. -
En el método
setUp(..)
, que se ejecuta antes de cada método@Test
, defina un estado de prueba de simulación común:code language-java @BeforeEach public void setUp() throws Exception { ctx.addModelsForClasses(BylineImpl.class); ctx.load().json("/com/adobe/aem/guides/wknd/core/models/impl/BylineImplTest.json", "/content"); }
- AEM
addModelsForClasses
registra el modelo Sling que se va a probar, en el contexto de ficticio, para que se pueda crear una instancia en los métodos@Test
. load().json
carga estructuras de recursos en el contexto ficticio, lo que permite que el código interactúe con estos recursos como si fueran proporcionados por un repositorio real. Las definiciones de recursos del archivoBylineImplTest.json
se cargan en el contexto JCR ficticio en /content.BylineImplTest.json
aún no existe, así que vamos a crearlo y definir las estructuras de recursos JCR necesarias para la prueba.
- AEM
-
Los archivos JSON que representan las estructuras de recursos ficticias se almacenan en core/src/test/resources, siguiendo la misma ruta de paquete que el archivo de prueba JUnit Java™.
Cree un archivo JSON en
core/test/resources/com/adobe/aem/guides/wknd/core/models/impl
llamado BylineImplTest.json con el siguiente contenido:code language-json { "byline": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "wknd/components/content/byline" } }
Este JSON define un recurso ficticio (nodo JCR) para la prueba unitaria de componentes Byline. En este punto, el JSON tiene el conjunto mínimo de propiedades necesarias para representar un recurso de contenido de componente Byline,
jcr:primaryType
ysling:resourceType
.Una regla general al trabajar con pruebas unitarias es crear el conjunto mínimo de contenido, contexto y código ficticio necesario para satisfacer cada prueba. Evite la tentación de crear un contexto ficticio completo antes de escribir las pruebas, ya que a menudo da como resultado artefactos innecesarios.
Ahora, con la existencia de BylineImplTest.json, cuando se ejecuta
ctx.json("/com/adobe/aem/guides/wknd/core/models/impl/BylineImplTest.json", "/content")
, las definiciones de recursos ficticias se cargan en el contexto en la ruta de acceso /content.
Prueba de getName() testing-get-name
Ahora que tenemos una configuración básica de contexto ficticio, vamos a escribir nuestra primera prueba para BylineImpl's getName(). Esta prueba debe garantizar que el método getName() devuelva el nombre creado correctamente almacenado en la propiedad "name" del recurso.
-
Actualice el método testGetName() en BylineImplTest.java de la siguiente manera:
code language-java import com.adobe.aem.guides.wknd.core.models.Byline; ... @Test public void testGetName() { final String expected = "Jane Doe"; ctx.currentResource("/content/byline"); Byline byline = ctx.request().adaptTo(Byline.class); String actual = byline.getName(); assertEquals(expected, actual); }
String expected
establece el valor esperado. Se establecerá en "Jane Listo".ctx.currentResource
establece el contexto del recurso ficticio con el que se evaluará el código, por lo que se establece en /content/byline, ya que ahí es donde se carga el recurso de contenido ficticio.Byline byline
crea una instancia del modelo Sling de firma electrónica adaptándolo desde el objeto de solicitud ficticia.String actual
invoca el método que estamos probando,getName()
, en el objeto del modelo Sling de firma.assertEquals
afirma que el valor esperado coincide con el valor devuelto por el objeto del modelo Sling de firma. Si estos valores no son iguales, la prueba fallará.
-
Ejecute la prueba… y se produce un error con
NullPointerException
.Esta prueba NO falla porque nunca definimos una propiedad
name
en el JSON de prueba, lo que provocará que la prueba falle, aunque la ejecución de la prueba no haya llegado a ese punto. Esta prueba falla debido a unNullPointerException
en el propio objeto de firma. -
En
BylineImpl.java
, si@PostConstruct init()
genera una excepción, se evita que el modelo Sling cree una instancia y se hace que el objeto del modelo Sling sea nulo.code language-java @PostConstruct private void init() { image = modelFactory.getModelFromWrappedRequest(request, request.getResource(), Image.class); }
Resulta que aunque el servicio OSGi de ModelFactory se proporciona a través de
AemContext
(a través de Apache Sling Context), no todos los métodos están implementados, incluidogetModelFromWrappedRequest(...)
al que se llama en el métodoinit()
de BylineImpl. Esto da como resultado un AbstractMethodError, que a término hace queinit()
falle y que la adaptación resultante dectx.request().adaptTo(Byline.class)
sea un objeto nulo.Dado que los simulacros proporcionados no pueden acomodar nuestro código, debemos implementar el contexto de simulación nosotros mismos. Para esto, podemos usar Mockito para crear un objeto ModelFactory de simulación, que devuelva un objeto Image de simulación cuando se invoque
getModelFromWrappedRequest(...)
sobre él.Dado que para crear una instancia del modelo Sling de firma, este contexto ficticio debe estar configurado, podemos agregarlo al método
@Before setUp()
. También necesitamos agregarMockitoExtension.class
a la anotación@ExtendWith
sobre la clase BylineImplTest.code language-java package com.adobe.aem.guides.wknd.core.models.impl; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.Mock; import com.adobe.aem.guides.wknd.core.models.Byline; import com.adobe.cq.wcm.core.components.models.Image; import io.wcm.testing.mock.aem.junit5.AemContext; import io.wcm.testing.mock.aem.junit5.AemContextExtension; import org.apache.sling.models.factory.ModelFactory; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import org.apache.sling.api.resource.Resource; @ExtendWith({ AemContextExtension.class, MockitoExtension.class }) public class BylineImplTest { private final AemContext ctx = new AemContext(); @Mock private Image image; @Mock private ModelFactory modelFactory; @BeforeEach public void setUp() throws Exception { ctx.addModelsForClasses(BylineImpl.class); ctx.load().json("/com/adobe/aem/guides/wknd/core/models/impl/BylineImplTest.json", "/content"); lenient().when(modelFactory.getModelFromWrappedRequest(eq(ctx.request()), any(Resource.class), eq(Image.class))) .thenReturn(image); ctx.registerService(ModelFactory.class, modelFactory, org.osgi.framework.Constants.SERVICE_RANKING, Integer.MAX_VALUE); } @Test void testGetName() { ... }
@ExtendWith({AemContextExtension.class, MockitoExtension.class})
marca la clase de caso de prueba para que se ejecute con la Extensión Jupiter Mockito JUnit, que permite el uso de las anotaciones @Mock para definir objetos de prueba en el nivel de clase.@Mock private Image
crea un objeto ficticio de tipocom.adobe.cq.wcm.core.components.models.Image
. Se define en el nivel de clase para que, según sea necesario, los métodos@Test
puedan modificar su comportamiento según sea necesario.@Mock private ModelFactory
crea un objeto ficticio de tipo ModelFactory. Esta es una burla de Mockito pura y no tiene métodos implementados. Se define en el nivel de clase para que, según sea necesario,@Test
los métodos puedan modificar su comportamiento según sea necesario.when(modelFactory.getModelFromWrappedRequest(..)
registra un comportamiento ficticio cuando se llama agetModelFromWrappedRequest(..)
en el objeto ModelFactory ficticio. El resultado definido enthenReturn (..)
es devolver el objeto de imagen ficticia. Este comportamiento solo se invoca cuando: el primer parámetro es igual al objeto de solicitud dectx
, el segundo parámetro es cualquier objeto Resource y el tercer parámetro debe ser la clase de imagen de los componentes principales. Aceptamos cualquier recurso porque en todas nuestras pruebas establecemosctx.currentResource(...)
en varios recursos de prueba definidos en BylineImplTest.json. Tenga en cuenta que agregamos la rigidez lenient() porque más adelante desearemos anular este comportamiento de ModelFactory.ctx.registerService(..)
. registra el objeto ModelFactory ficticio en AemContext, con la clasificación de servicio más alta. Esto es necesario porque la ModelFactory utilizada eninit()
de BylineImpl se inserta a través del campo@OSGiService ModelFactory model
. Para que AemContext inserte nuestro objeto de simulación, que administra las llamadas agetModelFromWrappedRequest(..)
, debemos registrarlo como el servicio de mayor clasificación de ese tipo (ModelFactory).
-
Vuelva a ejecutar la prueba y, de nuevo, fallará, pero esta vez el mensaje aclara por qué ha fallado.
Error de testGetName() debido a la afirmación
Recibimos un AssertionError que significa que la condición de aserción en la prueba falló y nos dice que el valor esperado es "Jane Doe" pero el valor real es nulo. Esto tiene sentido porque la propiedad "name" no se ha agregado a la definición de recurso /content/byline simulada en BylineImplTest.json, así que vamos a agregarla:
-
Actualizar BylineImplTest.json para definir
"name": "Jane Doe".
code language-json { "byline": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "wknd/components/content/byline", "name": "Jane Doe" } }
-
¡Vuelva a ejecutar la prueba y
testGetName()
ahora se aprobará!
Prueba de getOccupations() testing-get-occupations
¡Muy bien! ¡La primera prueba ha pasado! Vamos a pasar página y probar getOccupations()
. Dado que la inicialización del contexto ficticio se realizó en el método @Before setUp()
, esto está disponible para todos los métodos @Test
en este caso de prueba, incluido getOccupations()
.
Recuerde que este método debe devolver una lista ordenada alfabéticamente de ocupaciones (descendentes) almacenadas en la propiedad de ocupaciones.
-
Actualice
testGetOccupations()
de la siguiente manera:code language-java import java.util.List; import com.google.common.collect.ImmutableList; ... @Test public void testGetOccupations() { List<String> expected = new ImmutableList.Builder<String>() .add("Blogger") .add("Photographer") .add("YouTuber") .build(); ctx.currentResource("/content/byline"); Byline byline = ctx.request().adaptTo(Byline.class); List<String> actual = byline.getOccupations(); assertEquals(expected, actual); }
List<String> expected
define el resultado esperado.ctx.currentResource
establece el recurso actual para evaluar el contexto con respecto a la definición del recurso ficticio en /content/byline. Esto garantiza que BylineImpl.java se ejecute en el contexto de nuestro recurso ficticio.ctx.request().adaptTo(Byline.class)
crea una instancia del modelo Sling de firma electrónica adaptándolo desde el objeto de solicitud ficticia.byline.getOccupations()
invoca el método que estamos probando,getOccupations()
, en el objeto del modelo Sling de firma.assertEquals(expected, actual)
afirma que la lista esperada es la misma que la lista real.
-
Recuerde, al igual que
getName()
más arriba, BylineImplTest.json no define ocupaciones, por lo que esta prueba fallará si la ejecutamos, ya quebyline.getOccupations()
devolverá una lista vacía.Actualice BylineImplTest.json para incluir una lista de ocupaciones, y se establecen en orden no alfabético para garantizar que nuestras pruebas validen que las ocupaciones se ordenan alfabéticamente por
getOccupations()
.code language-json { "byline": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "wknd/components/content/byline", "name": "Jane Doe", "occupations": ["Photographer", "Blogger", "YouTuber"] } }
-
¡Corre la prueba, y de nuevo pasamos! ¡Parece que conseguir las ocupaciones ordenadas funciona!
testGetOccupations() supera
Prueba isEmpty() testing-is-empty
El último método para probar isEmpty()
.
La prueba isEmpty()
es interesante ya que requiere pruebas para diversas condiciones. Revisando el método isEmpty()
de BylineImpl.java se deben probar las siguientes condiciones:
- Devolver verdadero cuando el nombre está vacío
- Devolver verdadero cuando las ocupaciones son nulas o están vacías
- Devolver verdadero cuando la imagen es nula o no tiene URL de origen
- Devuelve "false" cuando el nombre, las ocupaciones y la imagen (con una URL src) están presentes
Para ello, necesitamos crear métodos de prueba, probar cada uno una condición específica y nuevas estructuras de recursos ficticios en BylineImplTest.json
para controlar estas pruebas.
Esta comprobación nos permitió omitir la prueba para cuando getName()
, getOccupations()
y getImage()
están vacíos, ya que el comportamiento esperado de ese estado se prueba mediante isEmpty()
.
-
La primera prueba probará la condición de un componente completamente nuevo que no tiene propiedades establecidas.
Agregue una nueva definición de recurso a
BylineImplTest.json
, asignándole el nombre semántico "empty"code language-json { "byline": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "wknd/components/content/byline", "name": "Jane Doe", "occupations": ["Photographer", "Blogger", "YouTuber"] }, "empty": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "wknd/components/content/byline" } }
"empty": {...}
define una nueva definición de recurso denominada "vacía" que solo tienejcr:primaryType
ysling:resourceType
.Recuerde que cargamos
BylineImplTest.json
enctx
antes de la ejecución de cada método de prueba en@setUp
, por lo que esta nueva definición de recurso está disponible de inmediato para nosotros en las pruebas de /content/empty. -
Actualice
testIsEmpty()
de la siguiente manera, estableciendo el recurso actual en la nueva definición de recurso de imitación "empty".code language-java @Test public void testIsEmpty() { ctx.currentResource("/content/empty"); Byline byline = ctx.request().adaptTo(Byline.class); assertTrue(byline.isEmpty()); }
Ejecute la prueba y asegúrese de que pasa.
-
A continuación, cree un conjunto de métodos para asegurarse de que si alguno de los puntos de datos necesarios (nombre, ocupaciones o imagen) está vacío,
isEmpty()
devuelve true.Para cada prueba, se usa una definición de recurso ficticio discreta, actualice BylineImplTest.json con las definiciones de recurso adicionales para sin nombre y sin ocupaciones.
code language-json { "byline": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "wknd/components/content/byline", "name": "Jane Doe", "occupations": ["Photographer", "Blogger", "YouTuber"] }, "empty": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "wknd/components/content/byline" }, "without-name": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "wknd/components/content/byline", "occupations": "[Photographer, Blogger, YouTuber]" }, "without-occupations": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "wknd/components/content/byline", "name": "Jane Doe" } }
Cree los siguientes métodos de prueba para probar cada uno de estos estados.
code language-java @Test public void testIsEmpty() { ctx.currentResource("/content/empty"); Byline byline = ctx.request().adaptTo(Byline.class); assertTrue(byline.isEmpty()); } @Test public void testIsEmpty_WithoutName() { ctx.currentResource("/content/without-name"); Byline byline = ctx.request().adaptTo(Byline.class); assertTrue(byline.isEmpty()); } @Test public void testIsEmpty_WithoutOccupations() { ctx.currentResource("/content/without-occupations"); Byline byline = ctx.request().adaptTo(Byline.class); assertTrue(byline.isEmpty()); } @Test public void testIsEmpty_WithoutImage() { ctx.currentResource("/content/byline"); lenient().when(modelFactory.getModelFromWrappedRequest(eq(ctx.request()), any(Resource.class), eq(Image.class))).thenReturn(null); Byline byline = ctx.request().adaptTo(Byline.class); assertTrue(byline.isEmpty()); } @Test public void testIsEmpty_WithoutImageSrc() { ctx.currentResource("/content/byline"); when(image.getSrc()).thenReturn(""); Byline byline = ctx.request().adaptTo(Byline.class); assertTrue(byline.isEmpty()); }
testIsEmpty()
comprueba la definición de recurso ficticio vacío y afirma queisEmpty()
es verdadero.testIsEmpty_WithoutName()
prueba una definición de recurso ficticio que tiene ocupaciones pero no tiene nombre.testIsEmpty_WithoutOccupations()
prueba una definición de recurso ficticio que tiene un nombre pero ninguna ocupación.testIsEmpty_WithoutImage()
prueba una definición de recurso ficticio con un nombre y ocupaciones, pero establece la imagen ficticia como nula. Tenga en cuenta que queremos anular el comportamientomodelFactory.getModelFromWrappedRequest(..)
definido ensetUp()
para garantizar que el objeto de imagen devuelto por esta llamada sea nulo. La función de código auxiliar de Mockito es estricta y no desea código duplicado. Por lo tanto, establecemos la configuración de simulación conlenient
para indicar explícitamente que se está anulando el comportamiento en el métodosetUp()
.testIsEmpty_WithoutImageSrc()
prueba una definición de recurso ficticio con un nombre y ocupaciones, pero establece la imagen ficticia para que devuelva una cadena en blanco cuando se invoca agetSrc()
. -
Por último, escriba una prueba para asegurarse de que isEmpty() devuelve false cuando el componente esté configurado correctamente. Para esta condición, podemos reutilizar /content/byline, que representa un componente Byline completamente configurado.
code language-java @Test public void testIsNotEmpty() { ctx.currentResource("/content/byline"); when(image.getSrc()).thenReturn("/content/bio.png"); Byline byline = ctx.request().adaptTo(Byline.class); assertFalse(byline.isEmpty()); }
-
Ahora ejecute todas las pruebas unitarias en el archivo BylineImplTest.java y revise el resultado del informe de prueba de Java™.
Ejecución de pruebas unitarias como parte de la compilación running-unit-tests-as-part-of-the-build
Las pruebas unitarias se ejecutan y son necesarias para pasarlas como parte de la compilación de Maven. Esto garantiza que todas las pruebas pasen correctamente antes de implementar una aplicación. La ejecución de los objetivos de Maven, como empaquetar o instalar, invoca automáticamente y requiere que se pasen todas las pruebas unitarias del proyecto.
$ mvn package
$ mvn package
Del mismo modo, si se cambia un método de prueba a failed, la compilación falla y se informa de qué prueba ha fallado y por qué.
Revise el código review-the-code
Vea el código terminado en GitHub o revise e implemente el código localmente en la rama Git tutorial/unit-testing-solution
.