Buenas tardes Me gustaría presentar una nueva herramienta para la prueba de extremo a extremo de microservicios - Catcher

¿Por qué probar?
¿Por qué necesito pruebas e2e? Martin Fowler recomienda evitarlo en favor de pruebas más simples.
Sin embargo, cuanto más altas son las pruebas, menos reescritura. Las pruebas unitarias se reescriben casi por completo. Las pruebas funcionales también tienen que pasar su tiempo en caso de refactorización grave. Las pruebas de extremo a extremo deberían probar la lógica empresarial, y cambia con menos frecuencia.
Además, incluso una cobertura de prueba completa de todos los microservicios no garantiza su interacción correcta. Los desarrolladores pueden implementar incorrectamente el protocolo (errores en el nombre / tipo de datos).
O implemente una nueva funcionalidad basada en el esquema de datos de la documentación, y obtenga una sorpresa en el entorno del producto en forma de errores de desajuste del esquema: un desastre en los datos o alguien olvidó actualizar el esquema de datos.
Y las pruebas de cada uno de los servicios involucrados serán verdes.
¿Por qué pruebas automáticas?
De verdad. En mi lugar de trabajo anterior, se decidió que pasar tiempo implementando pruebas automatizadas es demasiado largo, difícil y costoso. El sistema no es grande (10-15 microservicios con un kafka común). CTO decidió que "las pruebas no son importantes, lo principal es que el sistema funciona". Probado manualmente en varios entornos.
Cómo se veía (proceso general):
- De acuerdo con otros desarrolladores (implementando todos los microservicios que participan en la nueva funcionalidad)
- Implementar todos los servicios
- Conéctese a kafka remoto (doble ssh en dmz)
- Conectarse a los registros de k8s
- Forma manualmente y envía un mensaje a kafka (gracias a dios json)
- Observe los registros, tratando de entender si funcionó o no.
Y ahora hay un poco de alquitrán en este barril de chocolate: la mayoría de las pruebas deben ser creadas por los usuarios, porque reutilizar las existentes es difícil.
En primer lugar, debido al hecho de que el sistema está distribuido, varios servicios tenían sus propias bases de datos que contenían información sobre los usuarios.
En segundo lugar, kafka se utilizó para el almacenamiento permanente de datos. Es decir incluso si la información se elimina / cambia en la base de datos, el servicio la leerá nuevamente al reiniciar.
Cómo se veía el registro de un nuevo usuario de prueba (aproximadamente):
- Ingrese cualquier dato (nombre, correo, etc.)
- Introducción de datos personales (dirección, teléfono, cualquier información fiscal)
- Introducción de datos bancarios (en realidad, datos bancarios)
- Responda 20-40 preguntas (¿ya siente dolor?)
- Pase por la identificación IDNow (gracias, lo apagaron en el entorno de desarrollo, gracias, en el escenario son alrededor de 5 minutos o más, porque su caja de arena a veces está sobrecargada)
- En este paso, se requiere abrir una cuenta en un sistema de terceros y no se puede hacer nada a través del front-end. Debe ir por ssh a kafka y trabajar como un servidor simulado (envíe un mensaje de que la cuenta está abierta)
- A continuación, debe ir a otro front-end en la cuenta personal del moderador y confirmar al usuario.
Super, el usuario está registrado! Ahora una pequeña mosca en la pomada: algunas pruebas requieren más de 1 usuario de prueba. Y a veces las pruebas fallan la primera vez.
¿Y cómo es la verificación de la nueva funcionalidad y la confirmación del equipo de negocios?
Lo mismo debe repetirse en el siguiente entorno.
No hace falta decir que, después de un tiempo, comienza a sentirse como un mono, que solo hace lo que presiona, registrando a los usuarios.
Algunos otros desarrolladores (generalmente el front end) tuvieron problemas para conectarse a kafka. Y con un error en la terminal con una cadena de más de 80 caracteres (no todos sabían sobre tmux).
Pros :
- No es necesario configurar / escribir nada. Probar directamente en un entorno en ejecución.
- no requiere altas calificaciones (especialistas más baratos pueden hacerlo)
Contras :
- toma mucho tiempo (cuanto más, más)
- por lo general, solo se prueba una nueva funcionalidad (no está claro si la existente se ha roto)
- A menudo, los desarrolladores expertos se dedican a las pruebas manuales (los especialistas caros hacen un trabajo barato).
¿Cómo automatizar?
Si lees esto asintiendo con la cabeza y diciendo: "Sí, es un gran proceso, los chicos saben lo que están haciendo", entonces no te interesará.
Las pruebas caseras de e2e vienen en dos tipos y dependen de cuál de los programadores fue más libre:
- El backend que vive en su entorno de prueba. Protege la lógica de prueba, que se mueve a través de puntos finales. Incluso puede ser parcialmente automatizado debido a la interacción con CI.
- Un script con la misma lógica cableada. La única diferencia es que debes ir a algún lado y ejecutarlo desde allí. Si confía en su CI, incluso puede ejecutarlo automáticamente.
Eso suena bien Problemas?
Sí, tales pruebas están escritas en lo que la persona que las escribe sabe. Por lo general, estos son lenguajes de script como rub o python, que le permiten escribir este tipo de cosas de manera rápida y fácil. Sin embargo, a veces puedes toparte con un montón de scripts de bash, C o algo más exótico (pasé una semana copiando mi bicicleta en scripts de bash a python porque los scripts ya no eran extensibles y nadie sabía realmente cómo funcionaban y qué estaban probando) .
Ejemplo de proyecto aquí
Pros :
Contras :
- Son posibles requisitos adicionales para las calificaciones de los desarrolladores (si están desarrollando en Java, y las pruebas se escribieron en Python)
- escribir código para probar código escrito (¿quién probará las pruebas?)
¿Hay algo listo?
Por supuesto, solo mira en la dirección de BDD . Hay un pepino , hay un medidor .
En resumen, el desarrollador describe el escenario empresarial en un lenguaje especial, luego implementa los pasos del script en el código. El lenguaje suele ser legible para los humanos y se supone que será leído / escrito no solo por los desarrolladores, sino también por los gerentes de proyecto.
Los scripts junto con la implementación de los pasos también se encuentran en un proyecto separado y son ejecutados por productos de terceros (Cucumber / Gauge / ...).
El guión se ve así:
Customer sign-up ================ * Go to sign up page Customer sign-up ---------------- tags: sign-up, customer * Sign up a new customer with name "John" email "jdoe@test.de" and "password" * Check if the sign up was successful
E implementación:
@Step("Sign up as <customer> with email <test@example.com> and <password>") public void signUp(String customer, String email, String password) { WebDriver webDriver = Driver.webDriver; WebElement form = webDriver.findElement(By.id("new_user")); form.findElement(By.name("user[username]")).sendKeys(customer); form.findElement(By.name("user[email]")).sendKeys(email); form.findElement(By.name("user[password]")).sendKeys(password); form.findElement(By.name("user[password_confirmation]")).sendKeys(password); form.findElement(By.name("commit")).click(); } @Step("Check if the sign up was successful") public void checkSignUpSuccessful() { WebDriver webDriver = Driver.webDriver; WebElement message = webDriver.findElements(By.className("message")); assertThat(message.getText(), is("You have been signed up successfully!")); }
Proyecto completo aquí
Pros :
- La lógica de negocios se describe en un lenguaje legible y se almacena en un solo lugar (puede usarse como documentación)
- se utilizan soluciones listas para usar, los desarrolladores solo necesitan saber cómo usarlas
Contras :
- los gerentes no leerán ni escribirán guiones
- debe seguir tanto las especificaciones como su implementación (y esto es escribir código y editar especificaciones)
Bueno, entonces ¿por qué Catcher?
Por supuesto, para simplificar el proceso.
El desarrollador escribe solo scripts en json / yaml, y Catcher los ejecuta. El script consta de pasos ejecutados secuencialmente, por ejemplo:
steps: - http: post: url: '127.0.0.1/save_data' body: {key: '1', data: 'foo'} - postgres: request: conf: 'dbname=test user=test host=localhost password=test' query: 'select * from test where id=1'
Catcher admite plantillas jinja2, por lo que puede usar variables en lugar de valores cableados en el ejemplo anterior. Las variables globales se pueden almacenar en archivos de inventario (como en un conjunto), extraídas del entorno y registradas nuevas:
variables: bonus: 5000 initial_value: 1000 steps: - http: post: url: '{{ user_service }}/sign_up' body: {username: 'test_user_{{ RANDOM_INT }}', data: 'stub'} register: {user_id: '{{ OUTPUT.uuid }}' - kafka: consume: server: '{{ kafka }}' topic: '{{ new_users_topic }}' where: equals: {the: '{{ MESSAGE.uuid }}', is: '{{ user_id }}'} register: {balance: '{{ OUTPUT.initial_balance }}'}
Además, puede ejecutar pasos de prueba:
- check: # check user's initial balance equals: {the: '{{ balance }}', is: '{{ initial_value + bonus }}'}
También puede ejecutar algunos scripts desde otros scripts, lo que tiene un efecto excelente en la limpieza y reutilización del código (incluido el inicio de solo parte de los pasos a través del sistema de etiquetas, el lanzamiento retrasado, etc.).
include: file: register_user.yaml as: sign_up steps: # .... some steps - run: include: sign_up # .... some steps
Insertar y usar scripts puede resolver el problema de esperar un recurso (espere un servicio mientras se inicia).
Además de los pasos integrados listos para usar y un repositorio adicional), es posible escribir sus módulos en python (simplemente heredando de ExternalStep ) o en cualquier otro idioma:
y uso:
--- variables: one: 1 two: 2 steps: - math: add: {the: '{{ one }}', to: '{{ two }}'} register: {sum: '{{ OUTPUT }}'}
Las secuencias de comandos se colocan en el archivo acoplable y se ejecutan a través de CI.
También esta imagen se puede utilizar en Marathon / K8s para probar el entorno existente. En este momento estoy trabajando en un back-end (similar a AnsibleTower) para hacer que el proceso de prueba sea aún más fácil y conveniente.
Pros :
- no es necesario escribir código (solo en el caso de módulos personalizados)
- Cambiar entornos a través de archivos de inventario (como en conjunto)
- Puede usar sus propios módulos (en cualquier idioma, incluso sh)
Contras :
- sintaxis no legible para humanos (en comparación con las herramientas BDD)
En lugar de una conclusión
Cuando escribí esta herramienta, solo quería reducir el tiempo que generalmente paso en las pruebas. Sucedió que cada nueva compañía tiene que escribir (o reescribir) dicho sistema.
Sin embargo, la herramienta resultó ser más flexible de lo que esperaba. Si alguien está interesado en el artículo (o en la herramienta en sí), puedo decirle cómo usar Catcher para organizar migraciones centralizadas y actualizar el sistema de microservicio.
Upd
Como se me indicó en los comentarios, el tema no se revela.
Trataré de indicar aquí las tesis más controvertidas.
- Las pruebas de extremo a extremo no son pruebas unitarias. Ya me referí a M. Fowler en este artículo. Las pruebas unitarias se encuentran en el proyecto backend de prueba (directorio de
tests
estándar) y se ejecutan cada vez que el código cambia a CI. Y las pruebas e2e son un proyecto separado, generalmente demoran más, prueban la interacción de todos los servicios participantes y no saben nada sobre el código de su proyecto (recuadro negro). - no debe usar Catcher para las pruebas de integración (y siguientes). Es caro Es mucho más rápido escribir una prueba en su YP para el back-end actual. Necesita pruebas de extremo a extremo solo si la lógica de su negocio se distribuye en 2 o más servicios.
- Catcher también es un BDD. Desde mi punto de vista, la principal ventaja sobre Gauge / Cucumber son los módulos listos para usar y la facilidad de agregarlos. Idealmente, solo se escribe una prueba. En la última compañía, escribí las 4 pruebas en componentes estándar, sin programar nada. En consecuencia, los requisitos de calificación (y el precio de dicho especialista) serán más bajos. Solo se necesitan conocimientos de json / yaml y la capacidad de leer especificaciones.
- Para escribir pruebas de Catcher, tendrás que aprender Catcher-DSL. Por desgracia, es verdad. Al principio quería que las pruebas se escribieran por sí mismas, directamente desde el micrófono. Pero luego pensé que me despedirían como innecesario;) Como se mencionó anteriormente: Catcher DSL es el estándar json / yaml y las especificaciones de pasos. Nada fundamentalmente nuevo.
- Puede usar tecnologías estándar y escribir algo propio. Sin embargo, estamos hablando de microservicios. Esta es una gran cantidad de diferentes tecnologías y armas nucleares y una gran cantidad de equipos. Y si para el comando java junit + testcontainers es la elección obvia, el equipo de erlang elegirá otra cosa. En una empresa grande con más de 30 equipos en la parte superior, decidirán que todas las pruebas deben enviarse al nuevo equipo de infraestructura / qa. ¿Te imaginas lo felices que están en este zoológico?
- Si tiene 4-5 pruebas e2e, puede escribir todo en cualquier lenguaje de script y olvidarse de él. Sin embargo, si la lógica cambia con el tiempo, después de 2-4 años tendrá que refactorizar, distribuyendo directamente la lógica comercial de las pruebas y la implementación de métodos de acceso a los componentes probados. Así que al final escribes tu Catcher, pero no tan flexible. Me tomó 4 implementaciones para entender esto;)