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

NOTE
Si ha completado correctamente el capítulo anterior, puede volver a utilizar el proyecto y omitir los pasos para desproteger el proyecto de inicio.

Consulte el código de línea de base en el que se basa el tutorial:

  1. Consulte la rama tutorial/unit-testing-start de GitHub

    code language-shell
    $ cd aem-guides-wknd
    $ git checkout tutorial/unit-testing-start
    
  2. 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

  1. Comprender los conceptos básicos de las pruebas unitarias.
  2. AEM Obtenga información sobre los marcos de trabajo y las herramientas que se utilizan normalmente para probar el código de.
  3. 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:

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:

  1. JUnit5
  2. Marco de prueba de Mockito
  3. Apache Sling se burla
  4. 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.

  1. 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 -->.

  2. 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.
  3. 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.

Carpeta src de prueba unitaria

Ubicación donde se almacenan las pruebas unitarias.

  1. Cree una prueba unitaria para BylineImpl.java creando una nueva clase Java™ en src/test/java en una estructura de carpetas de paquetes Java™ que refleje la ubicación de la clase Java™ que se va a probar.

    Crear un nuevo archivo BylineImplTest.java

    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

    1. Identifíquelo fácilmente como el archivo de prueba para BylineImpl.java
    2. 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.

  1. 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");
        }
    }
    
  2. 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.

  3. 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.

BylineImplTest generado

core/src/test/java/com/adobe/aem/guides/wknd/core/models/impl/BylineImplTest.java

  1. 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.

    Ejecutar como prueba conjunta

    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 .

  1. 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 para AemContext 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.

  2. 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 archivo BylineImplTest.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.
  3. 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"
        }
    }
    

    BylineImplTest.json

    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 y sling: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.

  1. 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á.
  2. 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 un NullPointerException en el propio objeto de firma.

  3. 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, incluido getModelFromWrappedRequest(...) al que se llama en el método init() de BylineImpl. Esto da como resultado un AbstractMethodError, que a término hace que init() falle y que la adaptación resultante de ctx.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 agregar MockitoExtension.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 tipo com.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, @Testlos métodos puedan modificar su comportamiento según sea necesario.
    • when(modelFactory.getModelFromWrappedRequest(..) registra un comportamiento ficticio cuando se llama a getModelFromWrappedRequest(..) en el objeto ModelFactory ficticio. El resultado definido en thenReturn (..) es devolver el objeto de imagen ficticia. Este comportamiento solo se invoca cuando: el primer parámetro es igual al objeto de solicitud de ctx, 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 establecemos ctx.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 en init() 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 a getModelFromWrappedRequest(..), debemos registrarlo como el servicio de mayor clasificación de ese tipo (ModelFactory).
  4. Vuelva a ejecutar la prueba y, de nuevo, fallará, pero esta vez el mensaje aclara por qué ha fallado.

    afirmación de error de nombre de prueba

    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:

  5. 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"
        }
    }
    
  6. ¡Vuelva a ejecutar la prueba y testGetName() ahora se aprobará!

    nombre de prueba superado

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.

  1. 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.
  2. Recuerde, al igual que getName() más arriba, BylineImplTest.json no define ocupaciones, por lo que esta prueba fallará si la ejecutamos, ya que byline.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"]
        }
    }
    
  3. ¡Corre la prueba, y de nuevo pasamos! ¡Parece que conseguir las ocupaciones ordenadas funciona!

    Obtener ocupación aprobado

    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().

  1. 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 tiene jcr:primaryType y sling:resourceType.

    Recuerde que cargamos BylineImplTest.json en ctx 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.

  2. 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.

  3. 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 que isEmpty() 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 comportamiento modelFactory.getModelFromWrappedRequest(..) definido en setUp() 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 con lenient para indicar explícitamente que se está anulando el comportamiento en el método setUp().

    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 a getSrc().

  4. 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());
    }
    
  5. Ahora ejecute todas las pruebas unitarias en el archivo BylineImplTest.java y revise el resultado del informe de prueba de Java™.

Todas las pruebas superan

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

paquete mvn correcto

$ 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é.

error del paquete mvn

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.

recommendation-more-help
b2a561c1-47c0-4182-b8c1-757a197484f9