Búsqueda de sitios web

Pruebas continuas con microservicios (con ejemplos)


¿Cuándo es la arquitectura de microservicios el camino a seguir?

Elegir y diseñar la arquitectura correcta para un sistema es fundamental. Se debe garantizar la calidad de los requisitos del servicio y el manejo de los requisitos no funcionales, como la mantenibilidad, la extensibilidad y la capacidad de prueba.

La arquitectura de microservicios es una opción bastante recurrente en los ecosistemas más recientes después de que las empresas adoptaron Agile y DevOps. Si bien no es una opción de facto, cuando se trata de sistemas que están creciendo mucho y donde ya no es factible mantener una arquitectura monolítica, es una de las opciones preferidas. Mantener los componentes orientados al servicio y débilmente acoplados permite ciclos continuos de desarrollo y lanzamiento. Esto lleva a las empresas a probar y actualizar constantemente su software.

Los principales requisitos previos que exigen dicha arquitectura son:

  • Diseño basado en dominios
  • Entrega continua y cultura DevOps
  • Aislamiento de fallas
  • Descentralización

Tiene los siguientes beneficios:

  • Propiedad del equipo
  • Lanzamientos frecuentes
  • Mantenimiento más fácil
  • Actualizaciones más sencillas a versiones más nuevas
  • Agnóstico de la tecnología

Tiene las siguientes desventajas:

  • Mecanismos de comunicación de microservicio a microservicio.
  • Aumentar el número de servicios aumenta la complejidad general del sistema.

Cuanto más distribuida y compleja sea la arquitectura, más difícil será garantizar que el sistema pueda ampliarse y mantenerse mientras se controlan los costos y los riesgos. Una transacción comercial puede implicar múltiples combinaciones de protocolos y tecnologías. No se trata sólo de los casos de uso sino también de sus operaciones. Al adoptar enfoques ágiles y DevOps, se debe encontrar un equilibrio entre flexibilidad y funcionalidad con el objetivo de lograr revisiones y pruebas continuas.

La importancia de las estrategias de prueba en relación con los microservicios

La adopción de DevOps en una organización tiene como objetivo eliminar los distintos departamentos aislados y avanzar hacia un equipo general. Este movimiento busca mejorar específicamente las relaciones y procesos entre el equipo de software y el equipo de operaciones. Entregar a un ritmo más rápido también significa garantizar que haya pruebas continuas como parte del proceso de entrega de software. La implementación diaria (y en algunos casos incluso cada dos horas) es uno de los objetivos principales para una entrega rápida de soluciones empresariales de un extremo a otro. Aquí se deben tener en cuenta la confiabilidad y la seguridad, y aquí es donde entran las pruebas.

La inclusión del desarrollo basado en pruebas es la única manera de lograr una confianza genuina en que el código está listo para producción. Los casos de prueba válidos agregan valor al sistema ya que validan y documentan el sistema en sí. Aparte de eso, una buena cobertura de código fomenta mejoras y ayuda durante la refactorización.

La arquitectura de microservicios descentraliza los canales de comunicación, lo que complica las pruebas. No es un problema insuperable. Un equipo propietario de un microservicio no debe tener miedo de introducir cambios porque podrían dañar las aplicaciones cliente existentes. Las pruebas manuales son muy ineficientes, considerando que la integración continua y la implementación continua son las mejores prácticas actuales. Los ingenieros de DevOps deben asegurarse de incluir pruebas de automatización en su flujo de trabajo de desarrollo: escribir pruebas, agregar/refactorizar código y ejecutar pruebas.

Métodos comunes de prueba de microservicios

La pirámide de pruebas es un concepto sencillo que nos ayuda a identificar el esfuerzo requerido al escribir pruebas y dónde debería disminuir la cantidad de pruebas si disminuye la granularidad. También se aplica al considerar pruebas continuas para microservicios.

Para concretar el tema, abordaremos la prueba de un microservicio de muestra utilizando Spring Boot y Java. Las arquitecturas de microservicios, por definición, son más complicadas que la arquitectura monolítica. No obstante, nos centraremos en el tipo de pruebas y no en la arquitectura. Nuestros fragmentos se basan en un proyecto mínimo compuesto por un microservicio impulsado por API que posee un almacén de datos que utiliza MongoDB.

Pruebas unitarias

Las pruebas unitarias deberían ser la mayoría de las pruebas, ya que son rápidas, confiables y fáciles de mantener. Estas pruebas también se denominan pruebas de caja blanca. El ingeniero que los implementa está familiarizado con la lógica y está escribiendo la prueba para validar las especificaciones del módulo y verificar la calidad del código.

El foco de estas pruebas es una pequeña parte del sistema de forma aislada, es decir, la Clase Bajo Prueba (CUT). El Principio de Responsabilidad Única es una buena guía sobre cómo gestionar el código relacionado con la funcionalidad.

La forma más común de prueba unitaria es una “prueba unitaria solitaria”. “No traspasa fronteras y no necesita colaboradores aparte de la CUT.

Como lo señala Bill Caputo, las bases de datos, los canales de mensajería u otros sistemas son los límites; cualquier clase adicional utilizada o requerida por la CUT es colaboradora. Una prueba unitaria nunca debe cruzar un límite. Cuando se utilizan colaboradores, se escriben “pruebas unitarias sociables”. Usar simulacros de dependencias utilizadas por el CUT es una forma de probar código sociable con una “prueba unitaria solitaria”. "

En los modelos tradicionales de desarrollo de software, las pruebas de los desarrolladores aún no se habían adoptado de manera generalizada, por lo que las pruebas tenían que estar completamente fuera de sincronización con el desarrollo. Lograr una alta calificación de cobertura de código se consideró un indicador clave de la confianza del conjunto de pruebas.

Con la introducción de Agile y ciclos iterativos cortos, ahora es evidente que los modelos de prueba anteriores ya no funcionan. Se esperan cambios frecuentes de forma continua. Es mucho más importante probar el comportamiento observable que tener cubiertas todas las rutas del código. Las pruebas unitarias deberían tener más que ver con afirmaciones que con cobertura de código, porque el objetivo es verificar que la lógica funciona como se esperaba.

De nada sirve tener un componente con muchas pruebas y un alto porcentaje de cobertura de código cuando las pruebas no tienen las aserciones adecuadas. La aplicación de un enfoque más basado en el comportamiento (BDD) garantiza que las pruebas verifiquen el estado final y que el comportamiento coincida con los requisitos establecidos por la empresa. La ventaja de tener pruebas enfocadas con un alcance bien definido es que resulta más fácil identificar la causa del fallo. Las pruebas BDD nos dan una mayor confianza en que la falla fue consecuencia de un cambio en el comportamiento de las funciones. Las pruebas que de otro modo se centran más en la cobertura del código no pueden ofrecer mucha confianza, ya que habría un mayor riesgo de que la falla sea una repercusión de los cambios realizados en las pruebas mismas debido a los detalles de implementación de las rutas del código.

Las pruebas deben seguir la sugerencia de Martin Fowler cuando afirmó lo siguiente (en Refactoring: Improving the Design of Existing Code, segunda edición. Kent Beck y Martin Fowler. Addison-Wesley. 2018):

Otra razón para centrarse menos en detalles menores de implementación es la refactorización. Durante la refactorización, las pruebas unitarias deberían estar ahí para darnos confianza y no ralentizar el trabajo. Un cambio en la implementación del colaborador podría provocar un error en la prueba, lo que podría dificultar el mantenimiento de las pruebas. Se recomienda encarecidamente mantener un mínimo de pruebas unitarias sociables. Esto es especialmente cierto cuando dichas pruebas pueden ralentizar el ciclo de vida de desarrollo con la posibilidad de que las pruebas terminen siendo ignoradas. Una situación excelente para incluir una prueba unitaria sociable son las pruebas negativas, especialmente cuando se trata de verificación de comportamiento.

Pruebas de integración

Uno de los desafíos más importantes de los microservicios es probar su interacción con el resto de los servicios de infraestructura, es decir, los límites de los que depende una CUT en particular, como bases de datos u otros servicios. La pirámide de pruebas muestra claramente que las pruebas de integración deben ser menos que las pruebas unitarias pero más que las pruebas de componentes y de un extremo a otro. Estos otros tipos de pruebas pueden ser más lentos, más difíciles de escribir y mantener, y bastante frágiles en comparación con las pruebas unitarias. Cruzar límites puede tener un impacto en el rendimiento y el tiempo de ejecución debido al acceso a la red y a la base de datos; aun así, son indispensables, especialmente en la cultura DevOps.

En un ámbito de implementación continua, se prefieren las pruebas de integración estrechas en lugar de las pruebas de integración amplias. Esto último está muy cerca de las pruebas de un extremo a otro, donde requiere que el servicio real se ejecute en lugar del uso de una prueba doble de esos servicios para probar las interacciones del código. El principal objetivo a lograr es crear pruebas operativas manejables de una manera rápida, fácil y resistente. Las pruebas de integración se centran en la interacción del CUT con un servicio a la vez. Nos centramos en pruebas de integración estrecha. Se puede confirmar que la verificación de la interacción entre un par de servicios es la esperada, donde los servicios pueden ser un servicio de infraestructura o cualquier otro servicio.

Pruebas de persistencia

>

Un tipo de prueba controvertido es cuando se prueba la capa de persistencia, con el objetivo principal de probar las consultas y el efecto sobre los datos de prueba. Una opción es el uso de bases de datos en memoria. Algunos podrían considerar el uso de bases de datos en memoria como una prueba unitaria sociable, ya que es una prueba autónoma, idempotente y rápida. La prueba se ejecuta contra la base de datos creada con la configuración deseada. Después de ejecutar la prueba y verificar las afirmaciones, el almacén de datos se elimina automáticamente una vez que sale la JVM debido a su naturaleza efímera. Tenga en cuenta que todavía hay una conexión con un servicio diferente y se considera una prueba de integración limitada. En un enfoque de desarrollo basado en pruebas (TDD), dichas pruebas son esenciales ya que los conjuntos de pruebas deben ejecutarse en segundos. Las bases de datos en memoria son una compensación válida para garantizar que las pruebas se realicen lo más rápido posible y no se ignoren a largo plazo.

@Before
public void setup() throws Exception {
   try {
	// this will download the version of mongo marked as production. One should
	// always mention the version that is currently being used by the SUT
	String ip = "localhost";
	int port = 27017;

	IMongodConfig mongodConfig = new MongodConfigBuilder().version(Version.Main. PRODUCTION)
		.net(new Net(ip, port, Network.localhostIsIPv6())).build();

	MongodStarter starter = MongodStarter.getDefaultInstance();
mongodExecutable = starter.prepare(mongodConfig);
	mongodExecutable.start();

   } catch (IOException e) {
	e.printStackTrace();
   }
}

Fragmento 1: Instalación y puesta en marcha de MongoDB en memoria

Lo anterior no es una prueba de integración completa ya que una base de datos en memoria no se comporta exactamente como el servidor de base de datos de producción. Por lo tanto, no es una réplica del servidor mongo “real”, como sería el caso si se opta por pruebas de integración amplias.

Otra opción para las pruebas de integración de persistencia es ejecutar pruebas amplias conectadas a un servidor de base de datos real o con el uso de contenedores. Los contenedores alivian la molestia ya que, a pedido, uno aprovisiona la base de datos, en comparación con tener un servidor fijo. Tenga en cuenta que este tipo de pruebas requieren mucho tiempo y categorizar las pruebas es una posible solución. Dado que estas pruebas dependen de otro servicio que se ejecuta aparte de la CUT, se considera una prueba del sistema. Estas pruebas siguen siendo esenciales y, al utilizar categorías, se puede determinar mejor cuándo se deben ejecutar pruebas específicas para obtener el mejor equilibrio entre costo y valor. Por ejemplo, durante el ciclo de desarrollo, se podrían ejecutar sólo las pruebas de integración estrecha utilizando la base de datos en memoria. Las compilaciones nocturnas también podrían ejecutar pruebas que pertenezcan a una categoría como pruebas de integración amplia.

@Category(FastIntegration.class)
@RunWith(SpringRunner.class)
@DataMongoTest
public class DailyTaskRepositoryInMemoryIntegrationTest {
	. . . 
}

@Category(SlowIntegration.class)
@RunWith(SpringRunner.class)
@DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class DailyTaskRepositoryIntegrationTest {
   ...
}

Fragmento 2: Uso de categorías para diferenciar los tipos de pruebas de integración

Pruebas impulsadas por el consumidor

Los mecanismos de comunicación entre procesos (IPC) son un aspecto central de los sistemas distribuidos basados en una arquitectura de microservicios. Esta configuración plantea varias complicaciones durante la creación de conjuntos de pruebas. Además de eso, en un equipo ágil, los cambios están en progreso continuo, incluidos cambios en las API o eventos. No importa qué mecanismo IPC esté utilizando el sistema, existe la presencia de un contrato entre dos servicios cualesquiera. Existen varios tipos de contratos, según el mecanismo que se elija utilizar en el sistema. Cuando se utilizan API, el contrato es la solicitud y respuesta HTTP, mientras que en el caso de un sistema basado en eventos, el contrato es el evento del dominio en sí.

Un objetivo principal al probar microservicios es garantizar que esos contratos estén bien definidos y sean estables en cualquier momento. En un enfoque descendente de TDD, estas son las primeras pruebas que se cubren. Una prueba de integración fundamental garantiza que el consumidor tenga una respuesta rápida en cuanto un cliente no coincida con el estado real del productor con el que está hablando.

Estas pruebas deberían ser parte del proceso de implementación regular. Su fracaso permitiría a los consumidores tomar conciencia de que se ha producido un cambio por parte del productor y que se requieren cambios para volver a lograr la coherencia. Sin la necesidad de escribir pruebas complejas de un extremo a otro, las "pruebas de contratos impulsadas por el consumidor" se enfocarían en este caso de uso.

El siguiente es un ejemplo de un verificador de contrato generado por el complemento Spring-Cloud-Contract.

@Test
public void validate_add_New_Task() throws Exception {
  // given:
   MockMvcRequestSpecification request = given()
.header("Content-Type", "application/json;charset=UTF-8")
	.body("{"taskName":"newTask","taskDescription":"newDescription","isComplete":false,"isUrgent":true}");

  // when:
   ResponseOptions response = given().spec(request).post("/tasks");

  // then:
   assertThat(response.statusCode()).isEqualTo(200);
   assertThat(response.header("Content-Type")).isEqualTo("application/json;charset=UTF-8");
  // and:
   DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
   assertThatJson(parsedJson).field("['taskName']").isEqualTo("newTask");
   assertThatJson(parsedJson).field("['isUrgent']").isEqualTo(true);
   assertThatJson(parsedJson).field("['isComplete']").isEqualTo(false);
   assertThatJson(parsedJson).field("['id']").isEqualTo("3");
   assertThatJson(parsedJson).field("['taskDescription']").isEqualTo("newDescription");
}

Fragmento 3: Verificador de contrato generado automáticamente por el complemento Spring-Cloud-Contract

Una BaseClass escrita en el productor indica qué tipo de respuesta esperar en los distintos tipos de solicitudes mediante el uso de la configuración independiente. La colección empaquetada de stubs está disponible para que todos los consumidores puedan utilizarlos en su implementación. La complejidad surge cuando varios consumidores hacen uso del mismo contrato; por lo tanto, el productor necesita tener una visión global de los contratos de servicios requeridos.

@RunWith(SpringRunner.class)
@SpringBootTest
public class ContractBaseClass {

	@Autowired
	private DailyTaskController taskController;

	@MockBean
	private DailyTaskRepository dailyTaskRepository;

	@Before
	public void before() {
		RestAssuredMockMvc.standaloneSetup(this.taskController);
		Mockito.when(this.dailyTaskRepository.findById("1")).thenReturn(
Optional.of(new DailyTask("1", "Test", "Description", false, null)));
		
		. . . 
				
		Mockito.when(this.dailyTaskRepository.save(
new DailyTask(null, "newTask", "newDescription", false, true))).thenReturn(
new DailyTask("3", "newTask", "newDescription", false, true));
		
	}

Fragmento 4: la clase base del productor que define la respuesta esperada para cada solicitud

Del lado del consumidor, con la inclusión de la dependencia spring-cloud-starter-contract-stub-runner, configuramos la prueba para usar el binario stubs. Esta prueba se ejecutaría utilizando los códigos auxiliares generados por el productor según la configuración con la versión especificada o siempre la última. El artefacto stub vincula al cliente con el productor para garantizar que ambos estén trabajando en el mismo contrato. Cualquier cambio que se produzca se reflejaría en esas pruebas, y así, el consumidor identificaría si el productor ha cambiado o no.

@SpringBootTest(classes = TodayAskApplication.class)
@RunWith(SpringRunner.class)
@AutoConfigureStubRunner(ids = "com.cwie.arch:today:+:stubs:8080", stubsMode = StubRunnerProperties.StubsMode.LOCAL)
public class TodayClientStubTest {
 	 . . .
	@Test
	public void addTask_expectNewTaskResponse () {
		Task newTask = todayClient.createTask(
new Task(null, "newTask", "newDescription", false, true));
		BDDAssertions.then(newTask).isNotNull();
		BDDAssertions.then(newTask.getId()).isEqualTo("3");
		. . . 
		
	}
}

Fragmento 5: Consumidor inyectando la versión stub definida por el productor

Estas pruebas de integración verifican que la API de un proveedor todavía esté en línea con las expectativas de los consumidores. Al usar pruebas unitarias simuladas para API, habríamos eliminado las API y nos habríamos burlado del comportamiento. Desde el punto de vista del consumidor, este tipo de pruebas asegurarán que el cliente cumple con nuestras expectativas. Es esencial tener en cuenta que si el productor cambia la API, esas pruebas no fallarán. Y es imperativo definir qué cubre la prueba.

// the response we expect is represented in the task1.json file
private Resource taskOne = new ClassPathResource("task1.json");

@Autowired
private TodayClient todayClient;

@Test
public void createNewTask_expectTaskIsCreated() {
WireMock.stubFor(WireMock.post(WireMock.urlMatching("/tasks"))
		.willReturn(WireMock.aResponse()
		.withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
		.withStatus(HttpStatus.OK.value())
		.withBody(transformResourceJsonToString(taskOne))));
		
	Task tasks = todayClient.createTask(new Task(null, "runUTest", "Run Test", false, true));
	BDDAssertions.then(tasks.getId()).isEqualTo("1");

Fragmento 6: Una prueba de consumidor que hace afirmaciones sobre su propia respuesta definida

Pruebas de componentes

La arquitectura de microservicio puede crecer rápidamente y, por lo tanto, el componente bajo prueba podría integrarse con muchos otros componentes y múltiples servicios de infraestructura. Hasta ahora, hemos cubierto las pruebas de caja blanca con pruebas unitarias y pruebas de integración estrecha para probar el CUT que cruza el límite para integrarse con otro servicio.

El tipo más rápido de prueba de componentes es el enfoque en proceso, donde, junto con el uso de pruebas dobles y almacenes de datos en memoria, las pruebas permanecen dentro de los límites. La principal desventaja de este enfoque es que el servicio de producción desplegable no se prueba completamente; por el contrario, el componente requiere cambios para conectar la aplicación de manera diferente. El método preferido es la prueba de componentes fuera de proceso. Son como pruebas de un extremo a otro, pero con todos los colaboradores externos reemplazados por dobles de prueba, al hacerlo, se ejercita el artefacto completamente implementado haciendo uso de llamadas de red reales. La prueba sería responsable de configurar adecuadamente cualquier servicio externo como stub.

@Ignore
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { TodayConfiguration.class, TodayIntegrationApplication.class,
   CloudFoundryClientConfiguration.class })
public class BaseFunctionalitySteps {

   @Autowired
   private CloudFoundryOperations cf;

   private static File manifest = new File(".manifest.yml");

   @Autowired
   private TodayClient client;

   // Any stubs required 
   . . . 

   public void setup() {

cf.applications().pushManifest(PushApplicationManifestRequest.builder() 
 
 .manifest(ApplicationManifestUtils.read(manifest.toPath()).get(0)).build()).block();
}
. . .
// Any calls required by tests
public void requestForAllTasks() {
this.client.getTodoTasks();
}
}

Fragmento 7: Implementación del manifiesto en CloudFoundry y cualquier llamada requerida por las pruebas

Cloud Foundry es una de las opciones utilizadas para arquitecturas de prueba basadas en contenedores. “Es una plataforma de aplicaciones en la nube de código abierto que hace que sea más rápido y sencillo crear, probar, implementar y escalar aplicaciones. El siguiente es el manifest.yml, un archivo que define la configuración de todas las aplicaciones del sistema. Este archivo se utiliza para implementar el servicio real en el formato listo para producción en el espacio de la organización Pivotal donde el servicio MongoDB ya está configurado, coincidiendo con la versión de producción.

---
applications:
- name: today
  instances: 1
  path: ../today/target/today-0.0.1-SNAPSHOT.jar 
  memory: 1024M
  routes:
  - route: today.cfapps.io
  services:
  - mongo-it

Fragmento 8: Implementación de una instancia del servicio dependiendo del servicio mongo

Al optar por el enfoque fuera de proceso, tenga en cuenta que los límites reales están bajo prueba y, por lo tanto, las pruebas terminan siendo más lentas debido a que existen interacciones entre la red y la base de datos. Sería ideal tener esos conjuntos de pruebas escritos en un módulo separado. Poder ejecutarlos por separado en una etapa de Maven diferente en lugar de la fase habitual de "prueba".

Dado que el énfasis de las pruebas está en el componente mismo, las pruebas cubren las responsabilidades principales del componente y descuidan intencionalmente cualquier otra parte del sistema.

Cucumber, una herramienta de software que respalda el desarrollo basado en el comportamiento, es una opción para definir este tipo de pruebas de comportamiento. Con su analizador de lenguaje sencillo, Gherkin, garantiza que los clientes puedan comprender fácilmente todas las pruebas descritas. El siguiente archivo de funciones de Cucumber garantiza que la implementación de nuestro componente coincida con los requisitos comerciales para esa función en particular.

Feature: Tasks

Scenario: Retrieving one task from list
 Given the component is running
 And the data consists of one or more tasks
 When user requests for task x
 Then the correct task x is returned

Scenario: Retrieving all lists
 Given the data consists of one or more tasks
 When user requests for all tasks
 Then all tasks in database are returned

Scenario: Negative Test
 Given the component is not running
 When user requests for task x it fails with response 404

Fragmento 9: un archivo de características que define las pruebas BDD

Pruebas de un extremo a otro

Al igual que las pruebas de componentes, el objetivo de estas pruebas de un extremo a otro no es realizar cobertura de código sino garantizar que el sistema cumpla con los escenarios comerciales solicitados. La diferencia es que en las pruebas de un extremo a otro, todos los componentes están en funcionamiento durante la prueba.

Según el diagrama piramidal de pruebas, el número de pruebas de un extremo a otro disminuye aún más, teniendo en cuenta la lentitud que pueden provocar. El primer paso es ejecutar la configuración y, para este ejemplo, aprovecharemos docker.

version: '3.7'
services:
    today-app:
        image: today-app:1
        container_name: "today-app"
        build:
          context: ./
          dockerfile: DockerFile
        environment:
           - SPRING_DATA_MONGODB_HOST=mongodb
        volumes:
          - /data/today-app
        ports:
          - "8082:8080"
        links:
          - mongodb
        depends_on:
          - mongodb

    mongodb:
        image: mongo:3.2
        container_name: "mongodb"
        restart: always
        environment:
           - AUTH=no
           - MONGO_DATA_DIR=/data/db
           - MONGO_LOG_DIR=/dev/log
        volumes:
           - ./data:/data
        ports:
           - 27017:27017
        command: mongod --smallfiles --logpath=/dev/null # --quiet

Fragmento 10: La definición de docker.yml utilizada para implementar el servicio definido y la versión especificada de mongo como contenedores

En cuanto a las pruebas de componentes, tiene sentido mantener las pruebas de un extremo a otro en un módulo separado y en diferentes fases. El exec-maven-plugin se utilizó para implementar todos los componentes necesarios, ejecutar nuestras pruebas y, finalmente, limpiar y desmantelar nuestro entorno de pruebas.

Dado que se trata de una prueba de pila amplia, se ejecutará una selección más pequeña de pruebas por función. Las pruebas se seleccionan en función del riesgo empresarial percibido. Los tipos de pruebas anteriores cubrían detalles de bajo nivel. Eso significa si una historia de usuario coincide con los Criterios de Aceptación. Estas pruebas también deberían detener inmediatamente una versión, ya que una falla aquí podría causar graves repercusiones comerciales.

Conclusión

Las pruebas centradas en la transferencia a menudo terminan siendo un proceso muy largo, que demora hasta semanas hasta que se identifican, corrigen todos los errores y se prepara una nueva implementación. Los comentarios solo se reciben después de que se realiza un lanzamiento, lo que hace que la vida útil de una versión sea nuestro tiempo de respuesta más rápido posible.

El enfoque de prueba continua garantiza una retroalimentación inmediata. Lo que significa que el ingeniero de DevOps sabe inmediatamente si la característica implementada está lista para producción o no, dependiendo del resultado de las pruebas ejecutadas. Desde pruebas unitarias hasta pruebas de un extremo a otro, todas ayudan a acelerar el proceso de evaluación.

La arquitectura de microservicios ayuda a crear implementaciones más rápidas en producción, ya que está basada en dominios. Garantiza el aislamiento de fallos y aumenta la propiedad. Cuando varios equipos trabajan en el mismo proyecto, hay otra razón para adoptar dicha arquitectura: garantizar que los equipos sean independientes y no interfieran con el trabajo de los demás.

Mejore la capacidad de prueba avanzando hacia pruebas continuas. Cada microservicio tiene un dominio bien definido y su alcance debe limitarse a un actor. Los casos de prueba aplicados son específicos y más concisos, y las pruebas están aisladas, lo que facilita lanzamientos e implementaciones más rápidas.

Siguiendo el enfoque TDD, no hay codificación a menos que regrese una prueba fallida. Este proceso aumenta la confianza una vez que una implementación iterativa da como resultado una prueba exitosa. Este proceso implica que las pruebas se realizan en paralelo con la implementación real y todas las pruebas mencionadas anteriormente se ejecutan antes de que los cambios lleguen a un entorno de prueba. Las pruebas continuas siguen evolucionando hasta que ingresan a la siguiente etapa de lanzamiento, es decir, un entorno de prueba, donde el enfoque cambia a pruebas más exhaustivas, como las pruebas de carga.

Agile, DevOps y la entrega continua requieren pruebas continuas. El beneficio clave es la retroalimentación inmediata producida por las pruebas automatizadas. Las posibles repercusiones podrían influir en la experiencia del usuario, pero también tener consecuencias comerciales de alto riesgo. Para obtener más información sobre las pruebas continuas, comuníquese con phoenixNAP hoy.

Artículos relacionados