Prueba de unidad

Este tutorial cubre la implementación de una prueba de unidad que valida el comportamiento del modelo Sling del componente Byline, creado en la Componente personalizado tutorial.

Requisitos previos

Revise las herramientas e 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 más bajo al ejecutar las pruebas, lo que provoca errores de prueba. Si esto sucede, desinstale Java 8.

Proyecto de inicio

NOTA

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

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

  1. Consulte la tutorial/unit-testing-start ramificación desde GitHub

    $ cd aem-guides-wknd
    $ git checkout tutorial/unit-testing-start
    
  2. Implemente código base en una instancia de AEM local con sus habilidades con Maven:

    $ mvn clean install -PautoInstallSinglePackage
    
    NOTA

    Si utiliza AEM 6.5 o 6.4, añada la variable classic perfil a cualquier comando Maven.

    $ mvn clean install -PautoInstallSinglePackage -Pclassic
    

Siempre puede ver el código terminado en GitHub o desproteja el código localmente cambiando a la rama tutorial/unit-testing-start.

Objetivo

  1. Comprender los conceptos básicos de la prueba de unidades.
  2. Obtenga información sobre los marcos y las herramientas que se utilizan habitualmente para probar AEM código.
  3. Comprender las opciones para burlarse o simular recursos de AEM al escribir pruebas unitarias.

Fondo

En este tutorial, exploraremos cómo escribir Pruebas de unidad para el componente Byline Modelo de Sling (creado en el Creación de un componente de AEM 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 la salida de un método (o unidades de trabajo) frente a los resultados esperados.

Utilizaremos AEM prácticas recomendadas y usaremos:

Prueba de unidades y Adobe Cloud Manager

Adobe Cloud Manager integra la ejecución de la prueba de unidad y informes de cobertura de código en su canalización CI/CD para ayudar a fomentar y promover las mejores prácticas de prueba de unidades AEM código.

Aunque el código de prueba de unidades es una buena práctica para cualquier base de código, al utilizar Cloud Manager es importante aprovechar sus instalaciones de pruebas y creación de informes de calidad de código al proporcionar pruebas de unidades para que Cloud Manager se ejecute.

Actualizar las dependencias de Maven de prueba

El primer paso es inspeccionar las dependencias de Maven para admitir la escritura y ejecución de las pruebas. Se requieren cuatro dependencias:

  1. JUnit5
  2. Marco de pruebas de Mockito
  3. Mocks de Apache Sling
  4. AEM Mocks Test Framework (por io.wcm)

La variable JUnit5, Mockito y Mocks AEM las dependencias de prueba se añaden automáticamente al proyecto durante la configuración mediante la variable Arquetipo AEM Maven.

  1. Para ver estas dependencias, abra el POM del reactor principal en aem-guides-wknd/pom.xml, vaya a la <dependencies>..</dependencies> y ver las dependencias de JUnit, Mockito, Apache Sling Mocks y AEM Mock Tests por io.wcm en <!-- Testing -->.

  2. Asegúrese de que io.wcm.testing.aem-mock.junit5 está configurado como 4.1.0:

    <dependency>
        <groupId>io.wcm</groupId>
        <artifactId>io.wcm.testing.aem-mock.junit5</artifactId>
        <version>4.1.0</version>
        <scope>test</scope>
    </dependency>
    
    PRECAUCIÓN

    Tipo de archivo 35 genera el proyecto con io.wcm.testing.aem-mock.junit5 version 4.1.8. Cambie a 4.1.0 para seguir el resto de este capítulo.

  3. Apertura aem-guides-wknd/core/pom.xml y ver que las dependencias de prueba correspondientes están disponibles.

    Una carpeta de origen paralela en el core El proyecto contendrá las pruebas unitarias y cualquier archivo de prueba compatible. Esta prueba La carpeta proporciona una separación de las clases de prueba del código fuente, pero permite que las pruebas actúen como si estuvieran en los mismos paquetes que el código fuente.

Creación de la prueba JUnit

Las pruebas unitarias suelen asignar de 1 a 1 con clases Java. En este capítulo, escribiremos una prueba de JUnit para el BylineImpl.java, que es el modelo Sling que respalda el componente Byline.

Carpeta src de prueba unitaria

Ubicación en la que se almacenan las pruebas unitarias.

  1. Cree una prueba de unidad para el BylineImpl.java creando una nueva clase Java en src/test/java en una estructura de carpetas de paquetes Java que refleja 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 la clase Java de prueba unitaria correspondiente en

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

    La variable Test sufijo en el fichero de prueba unitaria, BylineImplTest.java es una convención, que nos permite

    1. Identificarlo fácilmente como el archivo de prueba para BylineImpl.java
    2. Pero también, diferencie el archivo de prueba from la clase que se esté probando, BylineImpl.java

Revisión de 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:

    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 JUnit's @BeforeEach, 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 marcado con la variable @Test anotación. 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, empezamos con un único método de prueba para cada método público en la clase que estamos probando, así que:

    BylineImpl.java BylineImplTest.java
    getName() es probado por testGetName()
    getOccupations() es probado por testGetOccupations()
    isEmpty() es 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 JUnit Test Case), cada método se marca con la variable @Test se ejecutará como una prueba que puede superar o fallar.

BylineImplTest generado

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

  1. Ejecute el JUnit Test Case haciendo clic con el botón derecho en el BylineImplTest.java y pulsando Ejecutar.
    Como se esperaba, todas las pruebas fallan, ya que aún no se han implementado.

    Ejecutar como prueba de junte

    Haga clic con el botón derecho en BylineImplTests.java > Ejecutar

Revisión de BylineImpl.java

Al escribir pruebas unitarias, hay dos enfoques principales:

  • Desarrollo impulsado por TDD o Test, lo que implica la escritura de las pruebas unitarias de forma incremental, inmediatamente antes de que se desarrolle la implementación; escriba una prueba, escriba la implementación para que se supere.
  • Implementación: primer desarrollo, que implica primero desarrollar código de trabajo y, después, escribir pruebas que validen dicho código.

En este tutorial, se utiliza el último enfoque (ya que ya hemos creado un BylineImpl.java en un capítulo anterior). Debido a esto, debemos revisar y entender el comportamiento de sus métodos públicos, pero también algunos de sus detalles de implementación. Esto puede sonar contrario, ya que una buena prueba sólo debería ocuparse de los insumos y los productos, pero al trabajar en AEM, hay una variedad de consideraciones de aplicación que es necesario entender para construir ensayos de trabajo.

En el contexto de la AEM, el TDD requiere un nivel de experiencia y es mejor que lo adopten los desarrolladores AEM que son expertos en AEM desarrollo y pruebas unitarias de AEM código.

Configuración AEM contexto de prueba

La mayoría del código escrito para AEM se basa en las API de JCR, Sling o AEM, que a su vez requieren que el contexto de una AEM en ejecución se ejecute correctamente.

Dado que las pruebas unitarias se ejecutan en la compilación, fuera del contexto de una instancia de AEM en ejecución, no existe dicho contexto. Para facilitar esto, AEM burlas de wcm.io crea un contexto de prueba que permite a estas API Principalmente actúa como si se estuvieran ejecutando en AEM.

  1. Crear un contexto de AEM utilizando de wcm.io AemContext en BylineImplTest.java añadiéndola como una extensión JUnit decorada con @ExtendWith a BylineImplTest.java archivo. La extensión se encarga de todas las tareas de inicialización y limpieza necesarias. Cree una variable de clase para AemContext que se puede utilizar para todos los métodos de prueba.

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

    Esta variable, ctx, expone un contexto de AEM de simulación que proporciona una serie de abstracciones de AEM y Sling:

    • El modelo de Sling de BylineImpl se registrará en este contexto
    • Se crean estructuras de contenido JCR simuladas en este contexto
    • Los servicios personalizados de OSGi se pueden registrar en este contexto
    • Proporciona una variedad de objetos de prueba y elementos de ayuda requeridos, como objetos SlingHttpServletRequest , una variedad de servicios de Sling y OSGi AEM como ModelFactory, PageManager, Page, Template, ComponentManager, Component, TagManager, Tag, etc.
      • Tenga en cuenta que no todos los métodos para estos objetos están implementados.
    • Y more!

    La variable ctx actuará como punto de entrada para la mayor parte de nuestro contexto de maqueta.

  2. En el setUp(..) método , que se ejecuta antes de cada @Test defina un estado común de prueba de prueba simulada:

    @BeforeEach
    public void setUp() throws Exception {
        ctx.addModelsForClasses(BylineImpl.class);
        ctx.load().json("/com/adobe/aem/guides/wknd/core/models/impl/BylineImplTest.json", "/content");
    }
    
    • addModelsForClasses registra el modelo de Sling que se va a probar, en el contexto de AEM simulación, para que se pueda crear una instancia en la variable @Test métodos.
    • load().json carga estructuras de recursos en el contexto de prueba, lo que permite que el código interactúe con estos recursos como si los hubiera proporcionado un repositorio real. Las definiciones de recursos del archivo BylineImplTest.json se cargan en el contexto JCR de prueba en /content.
    • BylineImplTest.json todavía no existe, por lo que vamos a crearlo y definir las estructuras de recursos JCR que son necesarias para la prueba.
  3. Los archivos JSON que representan las estructuras de recursos de prueba se almacenan en core/src/test/resources siguiendo las mismas rutas de paquetes que el archivo de prueba Java de JUnit.

    Cree un nuevo archivo JSON en core/test/resources/com/adobe/aem/guides/wknd/core/models/impl named BylineImplTest.json con el siguiente contenido:

    {
        "byline": {
        "jcr:primaryType": "nt:unstructured",
        "sling:resourceType": "wknd/components/content/byline"
        }
    }
    

    BylineImplTest.json

    Este JSON define un recurso de prueba (nodo JCR) para la prueba de unidad de componente Byline. En este punto, el JSON tiene el conjunto mínimo de propiedades necesarias para representar un recurso de contenido de componentes de línea, el jcr:primaryType y sling:resourceType.

    Una regla general al trabajar con pruebas unitarias es crear el conjunto mínimo de contenido falso, contexto y código necesario para satisfacer cada prueba. Evite la tentación de crear un contexto de burla completo antes de escribir las pruebas, ya que a menudo resulta en artefactos innecesarios.

    Ahora con la existencia de BylineImplTest.json, cuando ctx.json("/com/adobe/aem/guides/wknd/core/models/impl/BylineImplTest.json", "/content") se ejecuta, las definiciones de recursos de prueba se cargan en el contexto en la ruta /content.

Probando getName()

Ahora que tenemos una configuración básica de contexto de prueba, vamos a escribir nuestra primera prueba para getName() de BylineImpl. Esta prueba debe garantizar el método getName() devuelve el nombre de autor correcto almacenado en el "name" propiedad.

  1. Actualice el testGetName() en BylineImplTest.java de la siguiente manera:

    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. Estableceremos esto como "Jane Done".
    • ctx.currentResource establece el contexto del recurso de prueba con el que evaluar el código, por lo que se establece en /content/byline ya que allí es donde se carga el recurso de contenido de mock byline.
    • Byline byline crea una instancia del modelo de Sling de firma adaptándolo al objeto de solicitud de prueba.
    • String actual invoca el método que estamos probando, getName(), en el objeto Modelo Sling de firma.
    • assertEquals afirma que el valor esperado coincide con el valor devuelto por el objeto de firma del Modelo Sling. Si estos valores no son iguales, la prueba fallará.
  2. Ejecute la prueba… y falla con un NullPointerException.

    Tenga en cuenta que esta prueba NO falla porque nunca definimos un name en el JSON de prueba, lo que provocará que la prueba falle, pero la ejecución de la prueba no ha llegado a ese punto. Esta prueba falla debido a una NullPointerException en el propio objeto byline.

  3. En el BylineImpl.java, si @PostConstruct init() emite una excepción que impide que el Modelo Sling cree instancias de este y hace que el objeto del Modelo Sling sea nulo.

    @PostConstruct
    private void init() {
        image = modelFactory.getModelFromWrappedRequest(request, request.getResource(), Image.class);
    }
    

    Resulta que mientras que el servicio ModelFactory OSGi se proporciona a través del AemContext (a través del contexto Apache Sling), no todos los métodos están implementados, incluyendo getModelFromWrappedRequest(...) que se denomina en el informe de BylineImpl init() método. Esto da como resultado un AbstractMethodError, que en el término causa init() fallar y la adaptación resultante del ctx.request().adaptTo(Byline.class) es un objeto nulo.

    Dado que los burlas proporcionados no pueden acomodar nuestro código, debemos implementar el contexto de burla nosotros mismos Para esto, podemos usar Mockito para crear un objeto ModelFactory de broma, que devuelva un objeto de imagen de burla cuando getModelFromWrappedRequest(...) se invoca a él.

    Dado que, para crear incluso una instancia del modelo de Sling de Byline, este contexto de burla debe estar establecido, podemos agregarlo al @Before setUp() método. También es necesario agregar la variable MockitoExtension.class a @ExtendWith anotación encima de la BylineImplTest Clase .

    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 mayúsculas y minúsculas de prueba que se ejecutará con la variable Extensión de Mockito JUnit Jupiter que permite el uso de las @Mock anotaciones para definir objetos simulados en el nivel Class.
    • @Mock private Image crea un objeto de simulación de tipo com.adobe.cq.wcm.core.components.models.Image. Tenga en cuenta que esto se define en el nivel de clase para que, según sea necesario, @Test los métodos pueden modificar su comportamiento según sea necesario.
    • @Mock private ModelFactory crea un objeto de simulación de tipo ModelFactory. Tenga en cuenta que esta es una burla pura de Mockito y no tiene métodos implementados en ella. Tenga en cuenta que esto se define en el nivel de clase para que, según sea necesario, @Testlos métodos pueden modificar su comportamiento según sea necesario.
    • when(modelFactory.getModelFromWrappedRequest(..) registra el comportamiento de prueba para cuándo getModelFromWrappedRequest(..) se llama en el objeto ModelFactory falso. El resultado definido en thenReturn (..) es devolver el objeto de imagen de prueba. Tenga en cuenta que este comportamiento solo se invoca cuando: el primer parámetro es igual a la variable ctxdel objeto de solicitud de , el segundo parámetro es cualquier objeto de recurso y el tercer parámetro debe ser la clase de imagen de los componentes principales . Aceptamos cualquier recurso porque durante nuestras pruebas estableceremos la variable ctx.currentResource(...) a varios recursos de prueba definidos en la variable BylineImplTest.json. Tenga en cuenta que agregamos la variable lenient() restricción porque más tarde desearemos anular este comportamiento de ModelFactory.
    • ctx.registerService(..). registra el objeto ModelFactory falso en AemContext, con la clasificación de servicio más alta. Esto es necesario, ya que ModelFactory se usa en el init() se inyecta mediante la variable @OSGiService ModelFactory model campo . Para que AemContext se inyecte our objeto de prueba, que gestiona las llamadas a getModelFromWrappedRequest(..), debemos registrarlo como el Servicio de mayor rango de ese tipo (ModelFactory).
  4. Vuelva a ejecutar la prueba y, de nuevo, falla, pero esta vez el mensaje es claro por qué ha fallado.

    afirmación de error en el nombre de la prueba

    error testGetName() debido a una afirmación

    Recibimos un AssertionError lo que significa que la condición de aserción en la prueba ha fallado y nos dice que la variable El valor esperado es "Jane Doe" pero la variable el valor real es nulo. Esto tiene sentido porque "name" la propiedad no se ha agregado a mock /content/byline definición de recurso en BylineImplTest.json, así que vamos a agregarlo:

  5. Actualizar BylineImplTest.json para definir "name": "Jane Doe".

    {
        "byline": {
        "jcr:primaryType": "nt:unstructured",
        "sling:resourceType": "wknd/components/content/byline",
        "name": "Jane Doe"
        }
    }
    
  6. Vuelva a ejecutar la prueba y testGetName() ¡ahora pasa!

    pase de nombre de la prueba

Prueba de getOccupations()

¡Ok, bueno! ¡Nuestra primera prueba ha pasado! Sigamos adelante y probemos getOccupations(). Dado que la inicialización del contexto de prueba se realiza en la variable @Before setUp()método , estará disponible para todos @Test métodos en este caso de prueba, incluidos getOccupations().

Recuerde que este método debe devolver una lista ordenada alfabéticamente de ocupaciones (descendente) almacenadas en la propiedad occupations .

  1. Actualizar testGetOccupations() de la siguiente manera:

    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 defina el resultado esperado.
    • ctx.currentResource establece el recurso actual para evaluar el contexto en la definición de recurso de prueba en /content/byline. Esto garantiza que BylineImpl.java se ejecuta en el contexto de nuestro recurso de prueba.
    • ctx.request().adaptTo(Byline.class) crea una instancia del modelo de Sling de firma adaptándolo al objeto de solicitud de prueba.
    • byline.getOccupations() invoca el método que estamos probando, getOccupations(), en el objeto Modelo Sling de firma.
    • assertEquals(expected, actual) afirma que la lista esperada es la misma que la lista real.
  2. Recuerde, igual que getName() arriba, la variable BylineImplTest.json no define ocupaciones, por lo que esta prueba fallará si la ejecutamos, ya que byline.getOccupations() devolverá una lista vacía.

    Actualizar BylineImplTest.json para incluir una lista de ocupaciones, y se establecerán en orden no alfabético para garantizar que nuestras pruebas validen que las ocupaciones se ordenen alfabéticamente por getOccupations().

    {
        "byline": {
        "jcr:primaryType": "nt:unstructured",
        "sling:resourceType": "wknd/components/content/byline",
        "name": "Jane Doe",
        "occupations": ["Photographer", "Blogger", "YouTuber"]
        }
    }
    
  3. Ejecute la prueba, y de nuevo pasamos! ¡Parece que conseguir las ocupaciones ordenadas funciona!

    Obtener pase de ocupaciones

    pasadas testGetOccupations()

Testing isEmpty()

El último método para probar isEmpty().

Pruebas isEmpty() es interesante ya que requiere pruebas para una variedad de condiciones. Revisión BylineImpl.java's isEmpty() se deben probar las condiciones siguientes:

  • Devuelve true 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 dirección URL src
  • Devolver falso cuando el nombre, las ocupaciones y la imagen (con una URL src) están presentes

Para ello, es necesario crear nuevos métodos de prueba, cada uno de los cuales pruebe una condición específica, así como nuevas estructuras de recursos simulados en BylineImplTest.json para realizar estas pruebas.

Tenga en cuenta que esta comprobación nos permitió omitir las pruebas para cuándo getName(), getOccupations() y getImage() están vacías, 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 definidas.

    Agregue una nueva definición de recurso a BylineImplTest.json, dándole el nombre semántico "empty"

    {
        "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": {...} defina una nueva definición de recurso denominada “empty” que solo tenga un jcr:primaryType y sling:resourceType.

    Recuerde que cargamos BylineImplTest.json into 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 inmediatamente para nosotros en las pruebas de /content/empty.

  2. Actualizar testIsEmpty() de la siguiente manera, configurando el recurso actual en el nuevo "empty" simulen definición de recurso.

    @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 garantizar que si alguno de los puntos de datos necesarios (nombre, ocupación o imagen) está vacío, isEmpty() devuelve true.

    Para cada prueba, se utiliza una definición de recurso de prueba discreta, se actualiza BylineImplTest.json con las definiciones de recursos adicionales para sin nombre y sin ocupaciones.

    {
        "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.

    @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() prueba con la definición vacía del recurso de prueba y afirma que isEmpty() es verdadero.

    testIsEmpty_WithoutName() prueba con una definición de recurso de prueba que tiene ocupaciones pero no tiene nombre.

    testIsEmpty_WithoutOccupations() prueba con una definición de recurso de prueba que tiene un nombre pero no ocupaciones.

    testIsEmpty_WithoutImage() prueba con una definición de recurso de prueba con un nombre y ocupaciones, pero establece la imagen de prueba para que vuelva a ser nula. Tenga en cuenta que queremos anular la variable modelFactory.getModelFromWrappedRequest(..)comportamiento definido en setUp() para asegurarse de que el objeto Image devuelto por esta llamada sea nulo. La función de código auxiliar de Mockito es estricta y no desea código de código engañoso. Por lo tanto, nos ponemos la broma con lenient para indicar explícitamente que se anula el comportamiento en la variable setUp() método.

    testIsEmpty_WithoutImageSrc() prueba con una definición de recurso de prueba con un nombre y ocupaciones, pero establece la imagen de prueba para devolver una cadena en blanco cuando getSrc() se invoca a .

  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.

    @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 Java.

Todas las pruebas pasan

Ejecución de pruebas unitarias como parte de la compilación

Se requieren pruebas unitarias para pasar como parte de la compilación de maven. Esto garantiza que todas las pruebas pasen correctamente antes de que se implemente una aplicación. Al ejecutar los objetivos de Maven, como el paquete o la instalación, se invoca automáticamente y se requiere pasar todas las pruebas unitarias del proyecto.

$ mvn package

éxito del paquete mvn

$ mvn package

Del mismo modo, si cambiamos un método de prueba para que falle, la compilación falla e informa de qué prueba ha fallado y por qué.

error en el paquete mvn

Revisar el código

Ver el código terminado en GitHub o revisar e implementar el código localmente en la rama Git tutorial/unit-testing-solution.

En esta página