diff --git a/readme-es.md b/readme-es.md index 3325f51b..4cff008d 100644 --- a/readme-es.md +++ b/readme-es.md @@ -24,7 +24,7 @@ Empieza por comprender las técnicas de testing ubicuas que son la base de cualq - Consultor JavaScript & Node.js - 📗 [Testing Node.js & JavaScript de la A a la Z](https://www.testjavascript.com) - Mi curso completamente online con más de [10 horas de video](https://www.testjavascript.com), 14 tipos de test y más de 40 buenas practicas -- [Sígueme en Twitter ](https://twitter.com/goldbergyoni/) +- [Sígueme en Twitter](https://twitter.com/goldbergyoni/)
@@ -369,7 +369,7 @@ it("When a valid product is about to be deleted, ensure an email is sent", async ## ⚪ ️1.6 No uses “foo”, usa datos realistas -:white_check_mark: **Haz:** A menudo, los bugs de producción se revelan bajo una entrada muy específica y sorprendente: cuanto más realista sea la entrada de un test, mayores serán las posibilidades de detectar bugs temprano. Utiliza librerías dedicadas como [Faker] (https://www.npmjs.com/package/faker) para generar datos pseudo-reales que se asemejan en variedad y forma a los datos de producción. Por ejemplo, dichas librerías pueden generar números de teléfono realistas, nombres de usuario, tarjetas de crédito, nombres de empresas e incluso texto "lorem ipsum". También puedes crear algunos test (además de los test unitarios, no como un reemplazo) que aleatorizan los datos falsos para forzar la unidad que estamos testeando o incluso importar datos reales de su entorno de producción. ¿Quieres llevarlo al siguiente nivel? Ve la próxima sección (test basados en propiedades) +:white_check_mark: **Haz:** A menudo, los bugs de producción se revelan bajo una entrada muy específica y sorprendente: cuanto más realista sea la entrada de un test, mayores serán las posibilidades de detectar bugs temprano. Utiliza librerías dedicadas como [Faker] () para generar datos pseudo-reales que se asemejan en variedad y forma a los datos de producción. Por ejemplo, dichas librerías pueden generar números de teléfono realistas, nombres de usuario, tarjetas de crédito, nombres de empresas e incluso texto "lorem ipsum". También puedes crear algunos test (además de los test unitarios, no como un reemplazo) que aleatorizan los datos falsos para forzar la unidad que estamos testeando o incluso importar datos reales de su entorno de producción. ¿Quieres llevarlo al siguiente nivel? Ve la próxima sección (test basados en propiedades)
❌ **De lo contrario:** Todo tus test de desarrollo estarán en verde falsamente cuando uses datos sintéticos como "Foo", pero luego en producción pueden ponerse en rojo cuando un hacker use cadenas extrañas como “@3e2ddsf . ##’ 1 fdsfds . fds432 AAAA” @@ -467,7 +467,7 @@ Por otro lado, los tutoriales y herramientas basados en ‘classic snapshots’ Vale la pena señalar que hay algunos casos en los que los snapshoots grandes y externos son buenos - cuando comprobamos el esquema y no los datos (ignorando los valores y centrándonos en los campos) o en los casos en el que el documento no va a cambiar apenas en el tiempo
-❌ **De lo contrario:** Un test UI falla. El código parece correcto, la pantalla esta pintando todos los pixels correctamente, ¿que ha pasado? tu test de snapshoot ha encontrado una diferencia entre el origen y lo que ha recibido al ejecutarse: simplemente hay un espacio añadido en cualquier parte... +❌ **De lo contrario:** Un test UI falla. El código parece correcto, la pantalla esta pintando todos los pixels correctamente, ¿que ha pasado? tu test de snapshoot ha encontrado una diferencia entre el origen y lo que ha recibido al ejecutarse: simplemente hay un espacio añadido en cualquier parte...
@@ -741,7 +741,7 @@ Aprenda y practique [principios TDD](https://www.sm-cloud.com/book-review-test-d :white_check_mark: **Haz:** La [pirámide de test](https://martinfowler.com/bliki/TestPyramid.html), con 10> años de antigüedad, es un modelo excelente y relevante que sugiere tres tipos de test e influye en la estrategia de testeo de la mayoría de los desarrolladores. Al mismo tiempo, surgieron un puñado de nuevas y brillantes técnicas de testeo que se esconden en las sombras de la pirámide de test. Dados todos los cambios que hemos visto en los últimos 10 años (microservicios, cloud, serverless), ¿es posible que un modelo algo antiguo se adapte a *todos* los tipos de aplicaciones? ¿No debería el mundo del testing considerar aceptar nuevas técnicas? -No me malinterpretes, en 2019 la pirámide de test, el TDD y los test unitarios siguen siendo una técnica buena y probablemente sean la mejor combinación para muchas aplicaciones. Sólo como cualquier otro modelo, a pesar de su utilidad, [a veces debe estar equivocado] (https://en.wikipedia.org/wiki/All_models_are_wrong). Por ejemplo, considera una aplicación IOT que ingiere muchos eventos en un bus de mensajes como Kafka / RabbitMQ, que luego fluyen a algún data-warehouse y finalmente son consultados por alguna UI de análisis. ¿Realmente deberíamos gastar el 50% de nuestro presupuesto para test en escribir test unitarios para una aplicación que esté centrada en la integración y apenas tenga lógica? A medida que aumenta la diversidad de tipos de aplicaciones (bots, criptografía, Alexa-skills), aumentan las posibilidades de encontrar escenarios en los que la pirámide de test no sea la mejor opción +No me malinterpretes, en 2019 la pirámide de test, el TDD y los test unitarios siguen siendo una técnica buena y probablemente sean la mejor combinación para muchas aplicaciones. Sólo como cualquier otro modelo, a pesar de su utilidad, [a veces debe estar equivocado] (). Por ejemplo, considera una aplicación IOT que ingiere muchos eventos en un bus de mensajes como Kafka / RabbitMQ, que luego fluyen a algún data-warehouse y finalmente son consultados por alguna UI de análisis. ¿Realmente deberíamos gastar el 50% de nuestro presupuesto para test en escribir test unitarios para una aplicación que esté centrada en la integración y apenas tenga lógica? A medida que aumenta la diversidad de tipos de aplicaciones (bots, criptografía, Alexa-skills), aumentan las posibilidades de encontrar escenarios en los que la pirámide de test no sea la mejor opción Es hora de enriquecer el abanico de test y familiarizarse con más tipos de test (las siguientes secciones sugieren algunas ideas), modelos como la pirámide de test, pero también hacer coincidir los tipos de test con los problemas del mundo real al que te enfrentas ('Hola, nuestra API está rota, ¡escribamos contract testing dirigidos al consumidor!'), diversifica tus test como un inversor que construye una cartera de inversión basada en el análisis de riesgos — evalúa dónde pueden surgir problemas y combina algunas medidas de prevención para mitigar esos riesgos potenciales @@ -773,7 +773,7 @@ Una advertencia: el TDD en el mundo del software adopta una cara de falsa dicoto ## ⚪ ️2.2 Los test de Componentes pueden ser tu mejor amigo -:white_check_mark: **Haz:** +:white_check_mark: **Haz:** Cada test unitario cubre una pequeña parte de la aplicación y cubrirla totalmente cuesta muchísimo, mientras que los test end-to-end cubren fácilmente mucho terreno, pero son costosos y más lentos, ¿por qué no aplicar un enfoque equilibrado y escribir test más grandes que test unitarios pero más pequeños que los test end-to-end? Los test de componente es la canción no cantada del mundo del testing — proporcionan lo mejor de ambos mundos: rendimiento razonable y la posibilidad de aplicar patrones TDD + cobertura realista @@ -791,7 +791,6 @@ Los test de componente se centran en la 'unidad' de microservicios, funcionan co ### :clap: Ejemplo de cómo hacerlo correctamente: Supertest permite acercarse al API Express (rápido y cubre muchas capas) - ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Ejemplos con Mocha") ![alt text](assets/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) permite acercarse al API Express (rápido y cubre muchas capas)") @@ -802,7 +801,7 @@ Los test de componente se centran en la 'unidad' de microservicios, funcionan co ## ⚪ ️2.3 Asegúrate de que las nuevas versiones no rompan el API usando tests de contrato -:white_check_mark: **Haz:** Pongamos que tu microservicio tiene múltiples consumidores, y tenemos en ejecución diferentes versiones del servicio por compatibilidad (para que todos estén contentos). Luego cambias un campo y "¡boom!", uno de los consumidores que necesita ese campo se cabrea. Este es el Catch-22 del mundo de la integración: es muy difícil para el lado del servidor considerar todas las expectativas de todos los consumidores. Por otro lado, los consumidores no pueden realizar ningún test porque el servidor controla las fechas de release. [Los contratos dirigidos por el consumidor y el framework PACT] (https://docs.pact.io/) nacieron para regularizar este proceso con un enfoque muy disruptivo: no es el servidor quien define los test de sí mismo, sino que son los consumidores quienes definen los test de ¡el servidor! PACT puede registrar las expectativas del consumidor y dejarlas en una ubicación compartida, "broker", para que el servidor pueda cogerlas y cumplir con las expectativas y ejecutar cada construcción utilizando la librería PACT para detectar contratos incumplidos — una expectativa de consumidor no cumplida. Al hacerlo, todos los desajustes de la API cliente-servidor se detectan muy pronto durante la construcción / CI y pueden ahorrarte mucha frustración +:white_check_mark: **Haz:** Pongamos que tu microservicio tiene múltiples consumidores, y tenemos en ejecución diferentes versiones del servicio por compatibilidad (para que todos estén contentos). Luego cambias un campo y "¡boom!", uno de los consumidores que necesita ese campo se cabrea. Este es el Catch-22 del mundo de la integración: es muy difícil para el lado del servidor considerar todas las expectativas de todos los consumidores. Por otro lado, los consumidores no pueden realizar ningún test porque el servidor controla las fechas de release. [Los contratos dirigidos por el consumidor y el framework PACT] () nacieron para regularizar este proceso con un enfoque muy disruptivo: no es el servidor quien define los test de sí mismo, sino que son los consumidores quienes definen los test de ¡el servidor! PACT puede registrar las expectativas del consumidor y dejarlas en una ubicación compartida, "broker", para que el servidor pueda cogerlas y cumplir con las expectativas y ejecutar cada construcción utilizando la librería PACT para detectar contratos incumplidos — una expectativa de consumidor no cumplida. Al hacerlo, todos los desajustes de la API cliente-servidor se detectan muy pronto durante la construcción / CI y pueden ahorrarte mucha frustración
@@ -814,7 +813,7 @@ Los test de componente se centran en la 'unidad' de microservicios, funcionan co
-### :clap: Ejemplo de cómo hacerlo correctamente: +### :clap: Ejemplo de cómo hacerlo correctamente ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Ejemplos con PACT") @@ -826,7 +825,7 @@ Los test de componente se centran en la 'unidad' de microservicios, funcionan co ## ⚪ ️ 2.4 Testea tus middlewares aisladamente -:white_check_mark: **Haz:** Muchos evitan los test de middleware porque representan una pequeña porción del sistema y requieren ejecutar un servidor Express. Ambas razones son incorrectas — los middlewares son pequeños pero afectan a todas o la mayoría de las solicitudes y pueden testearse fácilmente como funciones puras que obtienen {req, res} objetos JS. Para testear una función de middleware se debe invocar y usar spy ([usando Sinon, por ejemplo] (https://www.npmjs.com/package/sinon)) sobre la interacción con los objetos {req, res} para garantizar que nuestra función middleware realiza la acción correcta. La librería [node-mock-http] (https://www.npmjs.com/package/node-mocks-http) lo lleva aún más lejos y factoriza los objetos {req, res} ademas de añadir el spy. Por ejemplo, puede asertar si el estado http que se estableció en el objeto res coincide con el esperado (consulta el ejemplo a continuación) +:white_check_mark: **Haz:** Muchos evitan los test de middleware porque representan una pequeña porción del sistema y requieren ejecutar un servidor Express. Ambas razones son incorrectas — los middlewares son pequeños pero afectan a todas o la mayoría de las solicitudes y pueden testearse fácilmente como funciones puras que obtienen {req, res} objetos JS. Para testear una función de middleware se debe invocar y usar spy ([usando Sinon, por ejemplo] ()) sobre la interacción con los objetos {req, res} para garantizar que nuestra función middleware realiza la acción correcta. La librería [node-mock-http] () lo lleva aún más lejos y factoriza los objetos {req, res} ademas de añadir el spy. Por ejemplo, puede asertar si el estado http que se estableció en el objeto res coincide con el esperado (consulta el ejemplo a continuación)
@@ -881,7 +880,7 @@ Crédito: ) es una librería JavaScript para mutation testing y la implementación es realmente clara: (1) cambia intencionalmente el código y "planta bugs". Por ejemplo, el código newOrder.price === 0 se convierte en newOrder.price! = 0. Estos "bugs" se llaman mutaciones @@ -1629,7 +1628,7 @@ it("Test addNewOrder, don't use such test names", () => { ## ⚪ ️4.4 Prevención de problemas de código de test con linters para test -:white_check_mark: **Haz:** ESLint tiene un conjunto de plugins específicos para inspeccionar patrones de código de test y descubrir problemas. Por ejemplo, [eslint-plugin-mocha] (https://www.npmjs.com/package/eslint-plugin-mocha) avisará cuando un test se escriba a nivel global (no es hijo de un describe () ) o cuando se omiten los test (https://mochajs.org/#inclusive-tests), lo que puede llevar a creer erróneamente de que todos los test están ok. Del mismo modo, [eslint-plugin-jest] (https://github.com/jest-community/eslint-plugin-jest) puede, por ejemplo, advertir cuando un test no tiene aserciones (sin verificar nada) +:white_check_mark: **Haz:** ESLint tiene un conjunto de plugins específicos para inspeccionar patrones de código de test y descubrir problemas. Por ejemplo, [eslint-plugin-mocha] () avisará cuando un test se escriba a nivel global (no es hijo de un describe () ) o cuando se omiten los test (), lo que puede llevar a creer erróneamente de que todos los test están ok. Del mismo modo, [eslint-plugin-jest] () puede, por ejemplo, advertir cuando un test no tiene aserciones (sin verificar nada)
@@ -1688,9 +1687,9 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test ## ⚪ ️ 5.2 Acorta el tiempo de feedback con local developer-CI -:white_check_mark: **Haz:** ¿Tienes un pipeline de CI con test, linter, verificación de vulnerabilidades, etc? Ayuda a los desarrolladores a ejecutarlo también localmente para solicitar comentarios instantáneos y acortar el [ciclo de feedback] (https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2 -circuitos de retroalimentacion/). ¿Por qué? un proceso de testing eficiente constituye muchos bucles iterativos: (1) test -> (2) feedback -> (3) refactor. Cuanto más rápido sea el feedback, más iteraciones de mejora puede realizar un desarrollador por módulo y perfeccionar los resultados. Por otro lado, cuando el feedback tarda en llegar, se podrían realizar menos iteraciones de mejora en un solo día, el equipo podría estar ya haciendo otra cosa / tarea / módulo y podría no estar listo para refinar ese módulo +:white_check_mark: **Haz:** ¿Tienes un pipeline de CI con test, linter, verificación de vulnerabilidades, etc? Ayuda a los desarrolladores a ejecutarlo también localmente para solicitar comentarios instantáneos y acortar el [ciclo de feedback] ( -circuitos de retroalimentacion/). ¿Por qué? un proceso de testing eficiente constituye muchos bucles iterativos: (1) test -> (2) feedback -> (3) refactor. Cuanto más rápido sea el feedback, más iteraciones de mejora puede realizar un desarrollador por módulo y perfeccionar los resultados. Por otro lado, cuando el feedback tarda en llegar, se podrían realizar menos iteraciones de mejora en un solo día, el equipo podría estar ya haciendo otra cosa / tarea / módulo y podría no estar listo para refinar ese módulo -En la practica, algunos proveedores de CI (Ejemplo: [CircleCI CLI local] (https://circleci.com/docs/2.0/local-cli/)) permiten ejecutar el pipeline localmente. Algunas herramientas comerciales como [wallaby proporcionan información valiosa y de test] (https://wallabyjs.com/) para el desarrollador sin coste. Alternativamente, puedes agregar scripts npm en el package.json para ejecutar todos los comandos de calidad (por ejemplo, test, linter, vulnerabilidades) - usa herramientas como [concurrently] (https://www.npmjs.com/package/concurrently) para paralelizarlas y que el código de salida sea distinto de cero si falla alguna de las herramientas. Ahora el desarrollador solo debe invocar un comando - por ejemplo "npm run quality": para obtener feedback en el acto. Considera también cancelar un commit si el control de calidad falla usando un githook ([husky puede ayudar] (https://github.com/typicode/husky)) +En la practica, algunos proveedores de CI (Ejemplo: [CircleCI CLI local] ()) permiten ejecutar el pipeline localmente. Algunas herramientas comerciales como [wallaby proporcionan información valiosa y de test] () para el desarrollador sin coste. Alternativamente, puedes agregar scripts npm en el package.json para ejecutar todos los comandos de calidad (por ejemplo, test, linter, vulnerabilidades) - usa herramientas como [concurrently] () para paralelizarlas y que el código de salida sea distinto de cero si falla alguna de las herramientas. Ahora el desarrollador solo debe invocar un comando - por ejemplo "npm run quality": para obtener feedback en el acto. Considera también cancelar un commit si el control de calidad falla usando un githook ([husky puede ayudar] ())
@@ -1783,7 +1782,7 @@ El enorme ecosistema de Kubernetes aún no tiene una herramienta estándar para
-### :clap: Ejemplo de cómo hacerlo correctamente: +### :clap: Ejemplo de cómo hacerlo correctamente ```javascript //instala license-checker en tu entorno de CI o localmente diff --git a/readme-fr.md b/readme-fr.md index fb8011e8..13baf15b 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -14,7 +14,7 @@ Ceci est un guide complet pour Javascript & Node.js de A à Z. Il résume et org Embarque pour un voyage qui va bien au-delà des bases et aborde des sujets avancés tels que les tests en production, les tests de mutations, les tests basés sur les propriétés et de nombreux autres outils stratégiques et professionnels. Si vous lisez chaque mot de ce guide, vos compétences de tests seront probablement bien au-dessus la moyenne. -## 🌐 Full-stack: front, backend, CI ... +## 🌐 Full-stack: front, backend, CI Commence par comprendre les pratiques de tests omniprésentes qui sont à la base de tout niveau d'application. Ensuite, plonge dans ton domaine de prédilection : frontend/UI, backend, CI ou peut-être tous ça à la fois ? @@ -24,11 +24,12 @@ Commence par comprendre les pratiques de tests omniprésentes qui sont à la bas - Un consultant JavaScript & Node.js - 📗 [Les tests Node.js & JavaScript de A à Z](https://www.testjavascript.com) - Mon cours en ligne complet avec plus de [10 heures de video](https://www.testjavascript.com), 14 types de tests et plus de 40 bonnes pratiques -- [Suis-moi sur Twitter ](https://twitter.com/goldbergyoni/) +- [Suis-moi sur Twitter](https://twitter.com/goldbergyoni/)
### Traductions - Lis dans la langue de ton choix + - 🇬🇧[Anglais](readme.md) - 🇨🇳[Chinois](readme-zh-CN.md) - Traduit par [Yves yao](https://github.com/yvesyao) - 🇰🇷[Coréen](readme.kr.md) - Traduit par [Rain Byun](https://github.com/ragubyun) @@ -76,7 +77,7 @@ Lignes directrices pour l'intégration continue dans le monde du JS (9 points) :white_check_mark: **À faire:** Le code des tests n'est pas comme le code de production - conçoit le pour être simple, court, sans abstraction, agréable à utiliser et minimaliste. En regardant le code d'un test, on doit pouvoir comprendre son but instantanément. -Nos esprits sont déjà occupés avec le code de production, on n'a pas "d'espace" pour de la complexité additionnelle. Si on essaye d'insérer un autre code compliqué dans nos pauvres cerveaux, l'équipe va être ralentie ce qui est en contradiction avec la raison pour laquelle on fait des tests. +Nos esprits sont déjà occupés avec le code de production, on n'a pas "d'espace" pour de la complexité additionnelle. Si on essaye d'insérer un autre code compliqué dans nos pauvres cerveaux, l'équipe va être ralentie ce qui est en contradiction avec la raison pour laquelle on fait des tests. En pratique, c'est là que de nombreuses équipes abandonnent tout simplement les tests. Les tests sont une opportunité pour autre chose - un assistant amical et souriant, un avec qui il est agréable de travailler et qui nous apporte beaucoup pour peu d'investissement. La science nous dit que l'on a deux systèmes cérébraux : le premier est utilisé pour les activités qui ne demandent pas d'effort comme conduire une voiture sur une route vide ; le deuxième sert aux opérations complexes et conscientes comme résoudre une équation mathématique. Conçois tes tests pour le premier système, lire un test doit _sembler_ aussi simple que de modifier un fichier HTML, et pas comme résoudre 2X(17 x 24). @@ -165,7 +166,6 @@ describe('Products Service', function() { ❌ **Autrement:** Non seulement, vous avez passé des heures à comprendre le code principal, mais en plus ce qui devait être la partie la plus simple de la journée (tester) vous tord le cerveau. -
Exemple de code @@ -318,7 +318,7 @@ it("White-box test: When the internal methods get 0 vat, it return 0 response", Avant d'utiliser des "test doubles", pose toi une question très simple: Est-ce que je l'utilise pour tester une fonctionnalité qui apparaît, ou peut apparaître, dans le document de spécification ? Si non, ça sent le test de boite blanche. -Par exemple, si tu veux tester que ton application se comporte correctement quand le service de paiement est coupé, tu peux faire un stub du service de paiement et déclencher une réponse de type 'No Response' pour vérifier que l'unité testée retourne la bonne valeur. Cela vérifie le comportement/réponse de notre application suivant un certain scénario. Tu peux aussi utiliser un spy pour vérifier qu'un email a bien été envoyé quand ce service était coupé - il s'agit encore une fois d'un test de comportement qui pourrait apparaître dans les spécifications ("Envoyer un email si le paiement n'as pas pu être enregistré"). +Par exemple, si tu veux tester que ton application se comporte correctement quand le service de paiement est coupé, tu peux faire un stub du service de paiement et déclencher une réponse de type 'No Response' pour vérifier que l'unité testée retourne la bonne valeur. Cela vérifie le comportement/réponse de notre application suivant un certain scénario. Tu peux aussi utiliser un spy pour vérifier qu'un email a bien été envoyé quand ce service était coupé - il s'agit encore une fois d'un test de comportement qui pourrait apparaître dans les spécifications ("Envoyer un email si le paiement n'as pas pu être enregistré"). D'un autre côté, si tu mock le service de paiement pour vérifier qu'il a bien été appelé avec le bon type Javascript, alors ton test est orienté sur des comportements internes qui n'ont rien à voir avec les fonctionnalités de l'application et changeront probablement fréquemment.
@@ -384,6 +384,7 @@ it("When a valid product is about to be deleted, ensure an email is sent", async
### :thumbsdown: Exemple d'anti pattern: Une suite de test qui passe à cause de données non réalistes + ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ```javascript @@ -683,6 +684,7 @@ describe("Order service", function() {
### :clap: Bien faire les choses, exemple: Structurer une suite avec le nom de l'unité testé et les scénarios mènera au rapport pratique montré ci-dessous + ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ```javascript @@ -738,7 +740,7 @@ Apprends et pratique [les principes TDD](https://www.sm-cloud.com/book-review-te ## ⚪ ️2.1 Enrichis ton portefeuille de test: Vois plus loin que les tests unitaire et la pyramide -:white_check_mark: **À faire:** La [pyramide de tests](https://martinfowler.com/bliki/TestPyramid.html), bien que vielle de plus de 10 ans, est un bon modèle qui suggère trois types de tests et influence la plupart des stratégies de tests des développeurs. Dans un même temps, une poignée de nouvelles techniques de tests brillantes ont émergé et sont dans l'ombre de la pyramide de tests. Étant donné l'étendu des changements que l'on a vu ces 10 dernières années (micro-services, cloud, serverless), est-il seulement possible qu'un vieux modèle soit adapté à *tout* les types d'applications ? Le monde du test ne devrait-il pas accueillir de nouvelles techniques ? +:white_check_mark: **À faire:** La [pyramide de tests](https://martinfowler.com/bliki/TestPyramid.html), bien que vielle de plus de 10 ans, est un bon modèle qui suggère trois types de tests et influence la plupart des stratégies de tests des développeurs. Dans un même temps, une poignée de nouvelles techniques de tests brillantes ont émergé et sont dans l'ombre de la pyramide de tests. Étant donné l'étendu des changements que l'on a vu ces 10 dernières années (micro-services, cloud, serverless), est-il seulement possible qu'un vieux modèle soit adapté à _tout_ les types d'applications ? Le monde du test ne devrait-il pas accueillir de nouvelles techniques ? Ne vous méprenez pas, en 2019, la pyramide de tests, le TDD et les tests unitaires sont toujours une technique puissante et sont probablement le meilleur choix pour beaucoup d'applications. Seulement, comme les autres modèles, malgré qu'il soit utile, [il doit être faux parfois](https://en.wikipedia.org/wiki/All_models_are_wrong). Par exemple, imagine une application IoT qui traite de nombreux événements dans une queue (message-bus) comme Kafka/RabbitMQ, qui vont ensuite dans un entrepot de donnée puis sont lus par une UI d'analyse. Est-ce qu'on devrait vraiment dépenser 50% de notre budget de test pour écrire des tests unitaires sur une application qui est centrée sur l'intégration et n'a presque aucune logique ? Plus la diversité des applications augmente (bots, crypto, Alexa-skills) plus les chances sont grandes de trouver un scénario ou la pyramide de test n'est pas le meilleur choix. @@ -808,7 +810,7 @@ Les tests de composant se concentrent sur "l'unité" du microservice, ils foncti
-### :clap: Bien faire les choses, exemple: +### :clap: Bien faire les choses, exemple ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") @@ -873,7 +875,7 @@ Credit:
{ ![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") -✅ **À faire:** Applique un monitoring active qui s'assure que le chargement de la page sur un vrai réseau est optimisé - ça inclue les questions UX comme un chargement lent ou un bundle non minifié. Le marché des outils d'inspection n'est pas petit: des outils basiques comme pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) peuvent être configuré rapidement pour vérifier sur le server est disponible et répond sous un délai raisonnable. Cela ne fait qu'effleurer la surface de ce qui pourrait aller mal, il est donc préférable de choisir des outils spécialisés pour le frontend (e.g [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) et d'effectuer une analyse plus complète. L'attention doit être portée sur les symptômes, les métriques qui affectent directement l'expérience utilisateur, comme le temps de chargement d'une page, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [le temps jusqu'à ce que la page devienne intéractive (TTI)](https://calibreapp.com/blog/time-to-interactive/). En plus de ça, on peut également surveiller les causes techniques, comme s'assurer que le contenu est complet, le temps jusqu'au premier byte, l'optimisation des images, s'assurer d'une taille de DOM raisonnable, SSL et autres. Il est recommandable d'avoir ces monitorings complets à la fois pendant le développement, dans le processus CI et surtout - 24h/24 7j/7 sur les serveurs/CDN de production +✅ **À faire:** Applique un monitoring active qui s'assure que le chargement de la page sur un vrai réseau est optimisé - ça inclue les questions UX comme un chargement lent ou un bundle non minifié. Le marché des outils d'inspection n'est pas petit: des outils basiques comme pingdom](), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) peuvent être configuré rapidement pour vérifier sur le server est disponible et répond sous un délai raisonnable. Cela ne fait qu'effleurer la surface de ce qui pourrait aller mal, il est donc préférable de choisir des outils spécialisés pour le frontend (e.g [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) et d'effectuer une analyse plus complète. L'attention doit être portée sur les symptômes, les métriques qui affectent directement l'expérience utilisateur, comme le temps de chargement d'une page, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [le temps jusqu'à ce que la page devienne intéractive (TTI)](https://calibreapp.com/blog/time-to-interactive/). En plus de ça, on peut également surveiller les causes techniques, comme s'assurer que le contenu est complet, le temps jusqu'au premier byte, l'optimisation des images, s'assurer d'une taille de DOM raisonnable, SSL et autres. Il est recommandable d'avoir ces monitorings complets à la fois pendant le développement, dans le processus CI et surtout - 24h/24 7j/7 sur les serveurs/CDN de production
❌ **Autrement:** Il doit être décevant de se rendre compte qu'après tout le soin apporté à la création d'une interface utilisateur, des tests 100% fonctionnels réussis et des bundles sophistiqué - l'expérience utilisateur est horrible et lente à cause d'une mauvaise configuration du CDN. @@ -1251,6 +1253,7 @@ test("movie title appears", async () => {
### :clap: Bien faire les choses, exemple: Stub ou intercepter les appels API + ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") ```javascript @@ -1300,7 +1303,7 @@ test("When no products exist, show the appropriate message", () => { ## ⚪ ️ 3.8 Accélérer les tests E2E en réutilisant les informations d'authentification -:white_check_mark: **à faire:** Dans des tests E2E qui incluent un vrai backend et utilisent un token utilisateur valide pour les appels API, ce n'est pas rentable d'isoler les tests à un niveau ou l'utilisateur est créé et authentifié à chaque requete. À la place, authentifie l'utilisateur une seule fois avant que l'exécution des tests commence (i.e before-all hook), enregistre le token en local et réutilise le dans les requetes. Ça semble violer un des principes de test principal - garder les tests autonomes sans associer les ressources. Même si c'est une inquiétude valide, dans les tests E2E la performance est une inquiétude clé et créer 1-3 requêtes API avant chaque test peut mener a un temps d'execution horrible. Réutiliser les informations d'authentification ne veut pas dire que les tests doivent agir sur la même entrée utilisateur - si le test compte sur les entrées utilisateur (e.g. test l'historique de paiement d'un utilisateur) alors assure toi de générer ces entrées dans le test et évite de les partager avec d'autres tests. Rappelle-toi aussi que le backend peut être simulé - Si les tests se concentrent sur le frontend, il vaut mieux les isoler et simuler l'API backend (voir point 3.6). +:white_check_mark: **à faire:** Dans des tests E2E qui incluent un vrai backend et utilisent un token utilisateur valide pour les appels API, ce n'est pas rentable d'isoler les tests à un niveau ou l'utilisateur est créé et authentifié à chaque requete. À la place, authentifie l'utilisateur une seule fois avant que l'exécution des tests commence (i.e before-all hook), enregistre le token en local et réutilise le dans les requetes. Ça semble violer un des principes de test principal - garder les tests autonomes sans associer les ressources. Même si c'est une inquiétude valide, dans les tests E2E la performance est une inquiétude clé et créer 1-3 requêtes API avant chaque test peut mener a un temps d'execution horrible. Réutiliser les informations d'authentification ne veut pas dire que les tests doivent agir sur la même entrée utilisateur - si le test compte sur les entrées utilisateur (e.g. test l'historique de paiement d'un utilisateur) alors assure toi de générer ces entrées dans le test et évite de les partager avec d'autres tests. Rappelle-toi aussi que le backend peut être simulé - Si les tests se concentrent sur le frontend, il vaut mieux les isoler et simuler l'API backend (voir point 3.6).
❌ **Autrement:** Si on prend 200 cas de tests et qu'on estime l'authentification à 100ms = 20 secondes simplement pour s'authentifier encore et encore @@ -1312,6 +1315,7 @@ test("When no products exist, show the appropriate message", () => {
### :clap: Bien faire les choses, exemple: Se connecter dans le before-all pas dans le before-each + ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") ```javascript @@ -1394,6 +1398,7 @@ Par exemple, certains frameworks permettent d'exprimer les parcours et les atten
### :clap: Bien faire les choses, exemple: Décrire les tests dans un language humain avec cucumber-js + ![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") ```javascript @@ -1414,6 +1419,7 @@ Feature: Twitter new tweet ``` ### :clap: Bien faire les choses, exemple: Visualiser nos composants, leurs états et entrées en utilisant Storybook + ![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") ![alt text](assets/story-book.jpg "Storybook") @@ -1755,7 +1761,7 @@ Le large écosystème de Kubernetes doit encore formaliser un outil standard pou
-### :clap: Bien faire les choses, exemple: +### :clap: Bien faire les choses, exemple ```javascript //install license-checker in your CI environment or also locally diff --git a/readme-pl.md b/readme-pl.md index 499f5e9d..fdbec392 100644 --- a/readme-pl.md +++ b/readme-pl.md @@ -718,7 +718,6 @@ test("Then there should not be a new transfer record", () => {}); :white_check_mark: **Opis:** Ten post skupia się na poradach dotyczących testowania, które są związane lub przynajmniej mogą być zilustrowane przykładem Node JS. Ten punkt zawiera jednak kilka dobrze znanych wskazówek niezwiązanych z Node - Uczyć się i ćwiczyć [zasady TDD](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — dla wielu są niezwykle cenne, ale nie przestrasz się, jeśli nie pasują do Twojego stylu, nie tylko tobie. Rozważ napisanie testów przed kodem w [style red-green-refactor](https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html), upewnij się, że każdy test sprawdza dokładnie jedną rzecz, gdy znajdziesz błąd - przed naprawą napisz test, który wykryje ten błąd w przyszłości, pozwól każdemu testowi zawieść co najmniej raz, zanim zmieni kolor na zielony, uruchom moduł, pisząc szybki i uproszczony kod, który satysfakcjonuje test - następnie stopniowo refaktoryzuj i przenieś go do poziomu klasy produkcyjnej, unikaj jakiejkolwiek zależności od środowiska (ścieżki, systemu operacyjnego itp.)
@@ -800,7 +799,7 @@ Testy komponentów koncentrują się na mikroserwisowej ‘jednostce’, działa
-### :clap: Przykład robienia tego dobrze: +### :clap: Przykład robienia tego dobrze ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") @@ -867,7 +866,7 @@ test("A request without authentication header, should return http status 403", (
-### :clap: Przykład robienia tego dobrze: CodeClimate, komercyjne narzędzie, które potrafi zidentyfikować złożone metody: +### :clap: Przykład robienia tego dobrze: CodeClimate, komercyjne narzędzie, które potrafi zidentyfikować złożone metody ![](https://img.shields.io/badge/🔧%20Example%20using%20Code%20Climate-blue.svg "Examples with CodeClimate") @@ -1172,7 +1171,6 @@ cy.wait("@products"); // wait for route to appear ### :clap: Przykład robienia tego dobrze: Biblioteka testująca, która czeka na elementy DOM - ```javascript // @testing-library/dom test("movie title appears", async () => { @@ -1242,7 +1240,6 @@ test("movie title appears", async () => { ❌ **W przeciwnym razie:** Średni test trwa nie dłużej niż kilka ms, typowe wywołanie API trwa 100 ms>, co powoduje, że każdy test ~20x wolniej -
Przykłady kodu @@ -1349,7 +1346,6 @@ beforeEach(setUser => () { ## ⚪ ️ 3.9 Zrób jeden smoke test E2E, który podróżuje po mapie witryny - :white_check_mark: **Opis:** W celu monitorowania produkcji i kontroli poprawności w czasie programowania uruchom pojedynczy test E2E, który odwiedzi wszystkie / większość stron witryny i zapewni, że nic się nie zepsuje. Ten rodzaj testu zapewnia duży zwrot z inwestycji, ponieważ jest bardzo łatwy do napisania i utrzymania, ale może wykryć wszelkiego rodzaju awarie, w tym problemy z funkcjonowaniem, siecią i wdrażaniem. Inne style sprawdzania smoke i sanity nie są tak niezawodne i wyczerpujące - niektóre zespoły ops po prostu pingują stronę główną (produkcję) lub programistów, którzy przeprowadzają wiele testów integracyjnych, które nie wykrywają problemów z pakowaniem i przeglądarką. Oczywiste jest, że smoke test nie zastępuje testów funkcjonalnych, a jedynie służy jako quick smoke detector
@@ -1763,7 +1759,7 @@ Ogromny ekosystem Kubernetes ma jeszcze sformalizować standardowe wygodne narz
-### :clap: Przykład robienia tego dobrze: +### :clap: Przykład robienia tego dobrze ```javascript //install license-checker in your CI environment or also locally diff --git a/readme-pt-br.md b/readme-pt-br.md index e127ab7d..49fdbebb 100644 --- a/readme-pt-br.md +++ b/readme-pt-br.md @@ -7,33 +7,35 @@
## 📗 45+ boas práticas: Super abrangente e exaustivo -Este é um guia para a confiabilidade JavaScript & Node.js da A-Z. Ele resume e organiza para você dezenas das melhores publicações, livros, ferramentas e postagens de blogs que o mercado tem a oferecer +Este é um guia para a confiabilidade JavaScript & Node.js da A-Z. Ele resume e organiza para você dezenas das melhores publicações, livros, ferramentas e postagens de blogs que o mercado tem a oferecer ## 🚢 Avançado: vai 10.000 milhas além do básico -Entre em uma jornada que vai muito além do básico, para tópicos avançados como testes em produção, testes de mutação, testes baseados em propriedades e muitas outras ferramentas estratégicas e profissionais. Se você ler todas as palavras deste guia, é provável que suas habilidades de teste superem a média +Entre em uma jornada que vai muito além do básico, para tópicos avançados como testes em produção, testes de mutação, testes baseados em propriedades e muitas outras ferramentas estratégicas e profissionais. Se você ler todas as palavras deste guia, é provável que suas habilidades de teste superem a média ## 🌐 Full-stack: front, backend, CI(Integração Contínua), qualquer coisa + Comece entendendo as práticas de teste onipresentes que são a base para qualquer camada de aplicativo. Em seguida, mergulhe na sua área de escolha: front-end/UI, back-end, CI(Integração Contínua) ou talvez todos eles?
### Escrito por Yoni Goldberg + * Um consultor JavaScript & Node.js * 👨‍🏫 [Minha oficina de testes](https://www.testjavascript.com) - aprenda sobre [meus workshops](https://www.testjavascript.com) na Europe & Estados Unidos -* [Me siga no twitter ](https://twitter.com/goldbergyoni/) +* [Me siga no twitter](https://twitter.com/goldbergyoni/) * Venha me ouvir falar em [LA](https://js.la/), [Verona](https://2019.nodejsday.it/), [Kharkiv](https://kharkivjs.org/), [free webinar](https://zoom.us/webinar/register/1015657064375/WN_Lzvnuv4oQJOYey2jXNqX6A). Eventos futuros TBD * [Newsletter informativo de qualidade sobre JavaScript](https://testjavascript.com/newsletter/) - insights e conteúdo apenas em assuntos estratégicos
### Traduções - leia em seu próprio idioma + * 🇨🇳[Chinese](readme-zh-CN.md) - cortesia de [Yves yao](https://github.com/yvesyao) * 🇰🇷[Korean](readme.kr.md) - cortesia de [Rain Byun](https://github.com/ragubyun) * Deseja traduzir para o seu próprio idioma? abra uma issue 💜 -

## `Índice` @@ -62,10 +64,8 @@ Observando o vigia - medindo a qualidade do teste (4 tópicos) Diretrizes para CI no mundo JS (9 tópicos) -

- # Seção 0️⃣: A Regra de Ouro
@@ -82,12 +82,11 @@ Os testes são uma oportunidade para outra coisa - um assistente amigável e sor Isso pode ser alcançado através de técnicas, ferramentas e alvos de teste selecionados de forma econômica, que são econômicos e proporcionam um ótimo ROI. Teste apenas o necessário, esforce-se para mantê-lo ágil, às vezes vale a pena abandonar alguns testes e trocar a confiabilidade por agilidade e simplicidade. ![alt text](/assets/headspace.png "Não temos espaço para complexidade adicional") - + A maioria dos conselhos abaixo são derivados desse princípio. ### Pronto para começar? -

# Seção 1: A Anatomia do Teste @@ -106,7 +105,6 @@ A maioria dos conselhos abaixo são derivados desse princípio.
- ❌ **Caso contrário:** Uma implantação acabou de falhar, um teste chamado "Adicionar produto" falhou. Isso diz o que exatamente está com defeito?
@@ -134,9 +132,11 @@ describe('Products Service', function() { }); ``` +
### :clap: Exemplo Fazendo Certo: um nome de teste que constitui 3 partes + ![alt text](/assets/bp-1-3-parts.jpeg "Um nome de teste que constitui 3 partes")
@@ -153,10 +153,8 @@ describe('Products Service', function() { 3rd A - Afirmar: Garanta que o valor recebido satisfaça a expectativa. Geralmente 1 linha de código -
- ❌ **Caso contrário:** Você não gasta apenas longas horas diárias para entender o código principal, agora também o que deveria ter sido a parte simples do dia (teste) estica seu cérebro
@@ -202,22 +200,15 @@ test('Should be classified as premium', () => { }); ``` -
- -

- - - ## ⚪ ️1.3 Descrever expectativas em um idioma do produto: use afirmações no estilo BDD :white_check_mark: **Faça:** Codificar seus testes em um estilo declarativo permite que o leitor entenda instantaneamente, sem gastar nem um único ciclo de CPU do cérebro. Quando você escreve um código imperativo, repleto de lógica condicional, o leitor entra em um estado mental de esforço. Nesse sentido, codifique a expectativa em uma linguagem humana, estilo declarativo de BDD usando expect ou should e não usando código personalizado. Se Chai e Jest não incluem a afirmação desejada e são altamente repetíveis, considere [estender o Jest matcher (Jest)](https://jestjs.io/docs/en/expect#expectextendmatchers) ou escrever um [plugin Chai personalizado](https://www.chaijs.com/guide/plugins/)
- ❌ **Caso Contrário:** A equipe escreverá menos testes e decorará os irritantes com .skip()
@@ -228,7 +219,7 @@ test('Should be classified as premium', () => { "Exemplos com Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20Jest-blue.svg "Exemplos com Jest") - ### :thumbsdown: Exemplo Anti-padrão: O leitor deve percorrer códigos não tão curtos e imperativos apenas para chegar a história do teste +### :thumbsdown: Exemplo Anti-padrão: O leitor deve percorrer códigos não tão curtos e imperativos apenas para chegar a história do teste ```javascript test("When asking for an admin, ensure only ordered admins in results" , () => { @@ -255,11 +246,11 @@ test("When asking for an admin, ensure only ordered admins in results" , () => { }); ``` +
### :clap: Exemplo Fazendo Certo: Percorrer o teste declarativo a seguir é fácil - ```javascript it("When asking for an admin, ensure only ordered admins in results" , () => { //supondo que adicionamos aqui dois administradores @@ -273,16 +264,13 @@ it("When asking for an admin, ensure only ordered admins in results" , () => { -

- ## ⚪ ️ 1.4 Atenha-se ao teste de caixa preta: teste apenas métodos públicos :white_check_mark: **Faça:** Testar os componentes internos gera uma enorme sobrecarga por quase nada. Se o seu código/API fornecer os resultados certos, você deve realmente investir suas próximas 3 horas em testes de COMO funcionou internamente e depois manter esses testes frágeis? Sempre que um comportamento público é verificado, a implementação privada também é implicitamente testada e seus testes serão interrompidos apenas se houver um determinado problema (por exemplo, saída incorreta). Essa abordagem também é chamada de teste comportamental. Por outro lado, se você testar os componentes internos (abordagem de caixa branca) — seu foco muda do planejamento do resultado do componente para detalhes minuciosos e seu teste pode ser interrompido devido a pequenas refatorações de código, embora os resultados sejam bons- isso aumenta drasticamente a carga de manutenção
- ❌ **Caso Contrário:** Seu teste se comporta como [O Pastor Mentiroso e o Lobo](https://pt.wikipedia.org/wiki/O_Pastor_Mentiroso_e_o_Lobo): gera falsos positivos (por exemplo, um teste falha porque um nome de variável privada foi alterado). Sem surpresa, as pessoas logo começarão a ignorar as notificações de IC até que um dia um bug real seja ignorado…
@@ -291,8 +279,10 @@ it("When asking for an admin, ensure only ordered admins in results" , () => {
### :thumbsdown: Exemplo Anti-padrão: Um caso de teste está testando os internos sem um bom motivo + ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20Mocha-blue.svg "Exemplos com Mocha & Chai") + ```javascript class ProductService{ //esse método é usado apenas internamente @@ -319,9 +309,6 @@ it("White-box test: When the internal methods get 0 vat, it return 0 response", - - -

## ⚪ ️ ️1.5 Escolha os dublês de teste certos: evite mocks a favor de stubs e spies @@ -333,7 +320,6 @@ Antes de usar dublês de teste, faça uma pergunta muito simples: Eu o uso para Por exemplo, se você quiser testar se seu aplicativo se comporta razoavelmente quando o serviço de pagamento estiver inativo, você pode desconsiderar (stub) o serviço de pagamento e acionar um retorno ‘No Response’ para garantir que a unidade em teste retorne o valor correto. Isso verifica o comportamento/resposta/resultado do aplicativo em certos cenários. Você também pode usar um spy para afirmar que um email foi enviado quando esse serviço está inoperante — isso é novamente uma verificação comportamental que provavelmente aparecerá em um documento de requisitos (“Envie um email se o pagamento não puder ser salvo”). Por outro lado, se você criar um mock do serviço de pagamento e garantir que ele foi chamado com os tipos de JavaScript certos— então seu teste será focado em itens internos que não tem nada a ver com a funcionalidade do aplicativo e provavelmente mudarão frequentemente
- ❌ **Caso Contrário:** Qualquer refatoração de código exige a pesquisa de todas as simulações no código e a atualização em conformidade. Os testes se tornam um fardo e não um amigo útil
@@ -343,8 +329,10 @@ Por exemplo, se você quiser testar se seu aplicativo se comporta razoavelmente
### :thumbsdown: Exemplo Anti-padrão: Mocks foca nos internos + ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20Sinon-blue.svg "Exemplo com Sinon") + ```javascript it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => { //Suponha que já adicionamos um produto @@ -355,6 +343,7 @@ it("When a valid product is about to be deleted, ensure data access DAL was call dataAccessMock.verify(); }); ``` +
### :clap: Exemplo Fazendo Certo: spies concentram-se em testar os requisitos, mas como efeito colateral inevitavelmente tocam os internos @@ -371,8 +360,6 @@ it("When a valid product is about to be deleted, ensure an email is sent", async - -

## ⚪ ️1.6 Não use “foo”, use dados de entrada realistas @@ -380,10 +367,8 @@ it("When a valid product is about to be deleted, ensure an email is sent", async :white_check_mark: **Faça:** Muitas vezes, os bugs de produção são revelados com informações muito específicas e surpreendentes— quanto mais realista for a entrada de teste, maiores serão as chances de detectar bugs mais cedo. Use bibliotecas dedicadas como [Faker](https://www.npmjs.com/package/faker) gerar dados pseudo-reais que se assemelham à variedade e forma dos dados de produção. Por exemplo, essas bibliotecas podem gerar números de telefone, nomes de usuários, cartões de crédito, nomes de empresas e até mesmo textos 'lorem ipsum' realistas. Você também pode criar alguns testes (além dos testes de unidade) que randomizam os dados dos fakers para esticar sua unidade sob teste ou até importar dados reais do seu ambiente de produção. Quer elevar para o próximo nível? Veja o próximo tópico (teste baseado em propriedades).
- ❌ **Caso Contrário:** Todos os seus testes de desenvolvimento parecerão falsamente verdes quando você usar entradas sintéticas como “Foo”, mas a produção poderá ficar vermelha quando um hacker passar uma string desagradável como “@ 3e2ddsf. ## '1 fdsfds. fds432 AAAA ” -
Códigos de Exemplo @@ -394,8 +379,7 @@ it("When a valid product is about to be deleted, ensure an email is sent", async ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20Jest-blue.svg "Exemplos com Jest") - - + ```javascript const addProduct = (name, price) =>{ const productNameRegexNoSpace = /^\S*$/;//nenhum espaço em branco permitido @@ -416,9 +400,11 @@ test("Wrong: When adding new product with valid properties, get successful confi }); ``` +
### :clap: Exemplo Fazendo Certo: Randomizando entrada realista + ```javascript it("Better: When adding new valid product, get successful confirmation", async () => { const addProductResult = addProduct(faker.commerce.productName(), faker.random.number()); @@ -431,9 +417,6 @@ it("Better: When adding new valid product, get successful confirmation", async (
- - -

## ⚪ ️ 1.7 Teste muitas combinações de entrada usando testes baseados em propriedades @@ -441,10 +424,8 @@ it("Better: When adding new valid product, get successful confirmation", async ( :white_check_mark: **Faça:** Normalmente, escolhemos algumas amostras de entrada para cada teste. Mesmo quando o formato de entrada se assemelha a dados do mundo real (veja o tópico ‘Não use foo’), cobrimos apenas algumas combinações de entrada (method(‘’, true, 1), method(“string” , false” , 0)), No entanto, em produção, uma API chamada com 5 parâmetros pode ser chamada com milhares de permutações diferentes, uma delas pode tornar nosso processo inativo ([consulte Teste do Fuzz](https://pt.wikipedia.org/wiki/Fuzzing)). E se você pudesse escrever um único teste que envie 1000 permutações de entradas diferentes automaticamente e capte para qual entrada nosso código falhou em retornar a resposta correta? O teste baseado em propriedades é uma técnica que faz exatamente isso: ao enviar todas as combinações de entradas possíveis para sua unidade em teste, aumenta a possibilidade de encontrar um bug. Por exemplo, dado um método — addNewProduct(id, name, isDiscount) — as bibliotecas de suporte chamarão esse método com muitas combinações de (number, string, boolean) como (1, “iPhone”, false), (2, “Galaxy”, true). Você pode executar testes baseados em propriedades usando seu test runner favorito (Mocha, Jest, etc) usando bibliotecas como [js-verify](https://github.com/jsverify/jsverify) ou [testcheck](https://github.com/leebyron/testcheck-js) (documentação muito melhor). Atualização: Nicolas Dubien sugere nos comentários abaixo [verificar check-fast](https://github.com/dubzzz/fast-check#readme) que parece oferecer alguns recursos adicionais e também ser mantido ativamente
- ❌ **Caso Contrário:** Inconscientemente, você escolhe as entradas de teste que cobrem apenas os caminhos de código que funcionam bem. Infelizmente, isso diminui a eficiência dos testes como veículo para expor caminhos de bugs que funcionam bem. -
Códigos de Exemplo @@ -474,9 +455,6 @@ describe("Product service", () => {
- - -

## ⚪ ️ 1.8 Se necessário, use apenas snapshots curtas e em linha @@ -488,7 +466,7 @@ Por outro lado, os tutoriais e ferramentas de "clássicos de snapshot" incentiva Vale ressaltar que existem poucos casos em que snapshots longos e externos são aceitáveis - ao afirmar no schema e não nos dados (extrair valores e focar em campos) ou quando o documento recebido raramente muda
-❌ **Caso Contrário:** Um teste de UI falha. O código parece correto, a tela renderiza pixels perfeitos, o que aconteceu? seu teste de snapshot acabou de encontrar uma diferença do documento de origem para o atual recebido - um único caractere de espaço foi adicionado ao markdown... +❌ **Caso Contrário:** Um teste de UI falha. O código parece correto, a tela renderiza pixels perfeitos, o que aconteceu? seu teste de snapshot acabou de encontrar uma diferença do documento de origem para o atual recebido - um único caractere de espaço foi adicionado ao markdown...
@@ -500,7 +478,7 @@ Vale ressaltar que existem poucos casos em que snapshots longos e externos são ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20Jest-blue.svg "Exemplos com Jest") - + ```javascript it('TestJavaScript.com is renderd correctly', () => { @@ -518,9 +496,11 @@ expect(receivedPage).toMatchSnapshot(); }); ``` +
### :clap: Exemplo Fazendo Certo: As expectativas são visíveis e focadas + ```javascript it('When visiting TestJavaScript.com home page, a menu is displayed', () => { //Ajeitar @@ -545,7 +525,6 @@ expect(menu).toMatchInlineSnapshot(` -

## ⚪ ️1.9 Evite acessórios de teste e sementes globais, adicione dados por teste @@ -553,10 +532,8 @@ expect(menu).toMatchInlineSnapshot(` :white_check_mark: **Faça:** Seguindo a regra de ouro (tópico 0), cada teste deve adicionar e agir em seu próprio conjunto de linhas de banco de dados para evitar o acoplamento e raciocinar facilmente sobre o fluxo de teste. Na realidade, isso geralmente é violado por testadores que propagam o banco de dados com dados antes de executar os testes ([também conhecido como "acessórios de teste"](https://en.wikipedia.org/wiki/Test_fixture)) por uma questão de melhoria de desempenho. Embora o desempenho seja realmente uma preocupação válida— pode ser mitigado (consulte o tópico "Teste de componentes"), no entanto, a complexidade do teste é uma tarefa muito dolorosa que deve governar outras considerações na maioria das vezes. Na prática, faça com que cada caso de teste inclua explicitamente os registros do banco de dados necessários e atue somente nesses registros. Se o desempenho se tornar uma preocupação crítica — um compromisso equilibrado pode vir na forma de propagação do único conjunto de testes que não está alterando dados (por exemplo, consultas)
- ❌ **Caso Contrário:** Poucos testes falham, uma implantação é abortada, nossa equipe gastará um tempo precioso agora, temos um bug? Vamos investigar, oh não - parece que dois testes estavam modificando os mesmos dados iniciais -
Códigos de Exemplo @@ -567,7 +544,7 @@ expect(menu).toMatchInlineSnapshot(` ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20Mocha-blue.svg "Exemplos com Mocha") - + ```javascript before(() => { //adicionando dados de sites e administradores ao nosso banco de dados. Onde estão os dados? lado de fora. Em alguma estrutura json ou de migração externa @@ -586,6 +563,7 @@ it("When querying by site name, get the right site", async () => { }); ``` +
### :clap: Exemplo Fazendo Certo: Podemos permanecer dentro do teste, cada teste atua em seu próprio conjunto de dados @@ -606,19 +584,17 @@ it("When updating site name, get successful confirmation", async () => {
-
## ⚪ ️ 1.10 Não pegue erros, espere-os + :white_check_mark: **Faça:** Ao tentar afirmar que alguma entrada aciona um erro, pode parecer correto usar try-catch-finally e afirmar que a entramos na cláusula catch. O resultado é um caso de teste estranho e detalhado (exemplo abaixo) que oculta a intenção simples do teste e as expectativas do resultado Uma alternativa mais elegante é o uso da asserção Chai dedicada de uma linha: expect(method).to.throw (ou no Jest: expect(method).toThrow()). É absolutamente obrigatório também garantir que a exceção contenha uma propriedade que indique o tipo de erro; caso contrário, apenas um erro genérico que o aplicativo não poderá fazer muito, em vez de mostrar uma mensagem decepcionante ao usuário
- ❌ **Caso contrário:** Será um desafio deduzir dos relatórios de teste (por exemplo, relatórios de IC) o que deu errado -
Códigos de Exemplo @@ -629,7 +605,7 @@ Uma alternativa mais elegante é o uso da asserção Chai dedicada de uma linha: ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20Mocha-blue.svg "Exemplos com Mocha") - + ```javascript it("When no product name, it throws error 400", async() => { let errorWeExceptFor = null; @@ -645,6 +621,7 @@ expect(errorWeExceptFor).not.to.be.null; }); ``` +
### :clap: Exemplo Fazendo Certo: Uma expectativa legível por humanos que pode ser entendida facilmente, talvez até pelo controle de qualidade ou pelo gerente de produto @@ -658,9 +635,6 @@ it.only("When no product name, it throws error 400", async() => {
- - -

## ⚪ ️ 1.11 Marque seus testes @@ -668,10 +642,8 @@ it.only("When no product name, it throws error 400", async() => { :white_check_mark: **Faça:** Testes diferentes devem ser executados em diferentes cenários: testes rápidos de fumaça, sem IO, devem ser executados quando um desenvolvedor salva ou dá commit em um arquivo, testes completos de ponta a ponta geralmente são executados quando uma nova pull request é enviada, etc. Isso pode ser alcançado marcando testes com palavras-chave como #cold #api #sanity para que você possa selecionar com sua ferramenta de teste e chamar o subconjunto desejado. Por exemplo, é assim que você invocaria apenas o grupo de teste de sanidade com Mocha: mocha — grep ‘sanity’
- ❌ **Caso Contrário:** A execução de todos os testes, incluindo testes que executam dezenas de consultas ao banco de dados, sempre que um desenvolvedor faz uma pequena alteração pode ser extremamente lenta e mantém os desenvolvedores longe de executar testes -
Códigos de Exemplo @@ -682,6 +654,7 @@ it.only("When no product name, it throws error 400", async() => { ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20Jest-blue.svg "Exemplos com Jest") + ```javascript //esse teste é rápido (sem banco de dados) e estamos marcando de forma correspondente //agora o usuário/IC pode executá-lo com frequência @@ -698,23 +671,19 @@ describe('Order service', function() {
- - -

## ⚪ ️1.12 Outra boa higiene genérica para testes + :white_check_mark: **Faça:** Esta postagem é focada em conselhos de teste relacionados ou pelo menos podem ser exemplificados com Node JS. Este tópico, no entanto, agrupa algumas dicas não relacionadas a Node que são bem conhecidas Aprenda e pratique [princípios TDD](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — eles são extremamente valiosos para muitos, mas não se intimidem se não se encaixarem no seu estilo, você não é o único. Considere escrever os testes antes do código em um [estilo vermelho-verde-refatorar](https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html), certifique-se de que cada teste verifica exatamente uma coisa, quando você encontrar um erro—antes de corrigir, escreva um teste que detectará esse erro no futuro, deixe que cada teste falhe pelo menos uma vez antes de ficar verde, inicie um módulo escrevendo um código rápido e simplista que satisfaça o teste - refatore gradualmente e leve-o a um nível de produção, evitar qualquer dependência do ambiente (caminhos, SO, etc)
- ❌ **Caso Contrário:** Você sentirá falta das pérolas de sabedoria que foram coletadas por décadas

- # Seção 2️⃣: Teste de Backend ## ⚪ ️2.1 Enriqueça seu portfólio de testes: Olhe além dos testes de unidade e da pirâmide @@ -729,10 +698,8 @@ Uma palavra de cautela: o argumento TDD no mundo do software tem uma cara típic
- ❌ **Caso Contrário:** Você perderá algumas ferramentas com um ROI incrível, algumas como Fuzz, lint e mutation podem fornecer valor em 10 minutos -
Códigos de Exemplo @@ -740,6 +707,7 @@ Uma palavra de cautela: o argumento TDD no mundo do software tem uma cara típic
### :clap: Exemplo Fazendo Certo: Cindy Sridharan sugere um rico portfólio de testes em seu incrível post "Testing Microservices - the sane way" + ![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan sugere um rico portfólio de testes em seu incrível post ‘Testing Microservices — the sane way’") ☺️Example:
[YouTube: “Além dos testes de unidade: 5 tipos de teste Node.JS brilhante (2018)” (Yoni Goldberg)](https://www.youtube.com/watch?v=-2zP494wdUY&feature=youtu.be) @@ -748,12 +716,8 @@ Uma palavra de cautela: o argumento TDD no mundo do software tem uma cara típic ![alt text](assets/bp-12-Yoni-Goldberg-Testing.jpeg "Um nome de teste que constitui 3 partes") -
- - -

## ⚪ ️2.2 O teste de componentes pode ser o seu melhor caso @@ -763,10 +727,8 @@ Uma palavra de cautela: o argumento TDD no mundo do software tem uma cara típic Os testes de componentes concentram-se na 'unidade' do Microsservico, eles trabalham contra a API, não fazem mock de nada que pertença ao próprio Microsserviço (por exemplo. banco de dados real ou pelo menos a versão na memória desse banco de dados) mas fazem stub (desconsideram) qualquer coisa externa como chamadas para outros Microsserviços. Ao fazer isso, testamos o que implementamos, abordamos o aplicativo de fora para dentro e obtemos grande confiança em um período de tempo razoável.
- ❌ **Caso Contrário:** Você pode passar longos dias escrevendo testes de unidade para descobrir que possui apenas 20% de cobertura do sistema -
Códigos de Exemplo @@ -789,40 +751,32 @@ Os testes de componentes concentram-se na 'unidade' do Microsservico, eles traba :white_check_mark: **Faça:** Então, seu Microsserviço possui vários clientes e você executa várias versões do serviço por motivos de compatibilidade (mantendo todos felizes). Então você muda algum campo e ‘boom!’, algum cliente importante que depende desse campo fica irritado. Este é o Catch-22 do mundo da integração: É muito desafiador para o lado do servidor considerar todas as múltiplas expectativas dos clientes— Por outro lado, os clientes não podem realizar nenhum teste porque o servidor controla as datas de lançamento. [Contratos orientados ao consumidor e o framework PACT](https://docs.pact.io/) nasceram para formalizar esse processo com uma abordagem muito perturbadora — não é o servidor que define o plano de teste por si mesmo, mas o cliente define os testes do… servidor! PACT pode gravar a expectativa do cliente e colocar em um local compartilhado, “corretor”, para que o servidor possa puxar as expectativas e executar em cada build usando a biblioteca PACT para detectar contratos quebrados— uma expectativa do cliente que não é atendida. Ao fazer isso, todas as incompatibilidades da API do servidor-cliente são detectadas cedo durante a compilação/IC e podem poupar muita frustração
- ❌ **Caso Contrário:** As alternativas são exaustivos testes manuais ou medo de implantação -
Códigos de Exemplo
-### :clap: Exemplo Fazendo Certo: +### :clap: Exemplo Fazendo Certo ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20PACT-blue.svg "Exemplos com PACT") - -![alt text](assets/bp-14-testing-best-practices-contract-flow.png ) +![alt text](assets/bp-14-testing-best-practices-contract-flow.png )
- -

- ## ⚪ ️ 2.4 Teste seus Middlewares isoladamente :white_check_mark: **Faça:** Muitos evitam os testes de Middleware porque representam uma pequena parte do sistema e requerem um servidor Express ativo. Ambas as razões estão erradas — Os Middlewares são pequenos, mas afetam todas ou a maioria das solicitações e podem ser testados facilmente como funções puras que recebem objetos JS {req, res}. Para testar uma função de middleware, basta invocá-la e espionar ([usando o Sinon por exemplo](https://www.npmjs.com/package/sinon)) na interação com os objetos {req, res} para garantir que a função executou a ação correta. A biblioteca [node-mock-http](https://www.npmjs.com/package/node-mocks-http) vai ainda mais longe e fatora os objetos {req, res}, além de espionar seu comportamento. Por exemplo, ela pode afirmar se o status http que foi definido no objeto res corresponde à expectativa (veja o exemplo abaixo)
- ❌ **Caso Contrário:** Um bug no middleware Express === um bug em todas ou na maioria das solicitações -
Códigos de Exemplo @@ -856,50 +810,42 @@ test('A request without authentication header, should return http status 403', (
- - -

## ⚪ ️2.5 Meça e refatore usando ferramentas de análise estática + :white_check_mark: **Faça:** O uso de ferramentas de análise estática ajuda a fornecer maneiras objetivas de melhorar a qualidade do código e manter seu código sustentável. Você pode adicionar ferramentas de análise estática à sua compilação de IC para abortar quando encontrar mal cheiros no código. Suas principais vantagens em relação a usar simplesmente um linter são a capacidade de inspecionar a qualidade no contexto de vários arquivos (por exemplo. detectar duplicações), executar análise avançada (por exemplo, complexidade do código) e seguir o histórico e o progresso dos problemas de código. Dois exemplos de ferramentas que você pode usar são: [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube)) e [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate)) Créditos:: [Keith Holliday](https://github.com/TheHollidayInn)
- ❌ **Caso Contrário:** Com baixa qualidade de código, bugs e desempenho sempre serão um problema que nenhuma nova biblioteca brilhante ou recursos avançados podem corrigir -
Códigos de Exemplo
-### :clap: Exemplo Fazendo Certo: CodeClimate, uma ferramenta comercial que pode identificar métodos complexos: +### :clap: Exemplo Fazendo Certo: CodeClimate, uma ferramenta comercial que pode identificar métodos complexos ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20Code%20Climate-blue.svg "Exemplos com CodeClimate") - + ![alt text](assets/bp-16-yoni-goldberg-quality.png " CodeClimat, uma ferramenta comercial que pode identificar métodos complexos:")
- - -

## ⚪ ️ 2.6 Verifique sua preparação para o caos relacionado ao Node + :white_check_mark: **Faça:** Estranhamente, a maioria dos testes de software trata apenas de lógica e dados, mas algumas das piores coisas que acontecem (e são realmente difíceis de mitigar) são questões de infra-estrutura. Por exemplo, você já testou o que acontece quando a memória do processo está sobrecarregada, ou quando o servidor/processo morre, ou o seu sistema de monitoramento percebe quando a API fica 50% mais lenta?. Para testar e mitigar esse tipo de coisas ruins — [Chaos engineering](https://principlesofchaos.org/) nasceu pela Netflix. O objetivo é fornecer conscientização, frameworks e ferramentas para testar a resiliência de nosso aplicativo para problemas caóticos. Por exemplo, uma de suas famosas ferramentas, [o chaos monkey](https://github.com/Netflix/chaosmonkey), mata servidores aleatoriamente para garantir que nosso serviço ainda possa atender usuários e não depender em um único servidor (existe também uma versão para Kubernetes, [kube-monkey](https://github.com/asobti/kube-monkey), que mata pods). Todas essas ferramentas funcionam no nível de hospedagem/plataforma, mas e se você quiser testar e gerar o caos puro do Node, por exemplo verificar como o processo do nó lida com erros não detectados, rejeições de promises não tratadas, Memória do v8 sobrecarregada com o máximo permitido de 1,7 GB ou se o seu UX permanece satisfatório quando o loop de eventos é bloqueado com frequência? para resolver isso que escrevi, [node-chaos](https://github.com/i0natan/node-chaos-monkey) (alpha) que fornece todos os tipos de atos caóticos relacionados ao Node
- ❌ **Caso Contrário:** Não há escapatória aqui, a lei de Murphy afetará sua produção sem piedade -
Códigos de Exemplo @@ -907,6 +853,7 @@ Créditos:: @@ -918,10 +865,8 @@ Créditos:: - ❌ **Caso Contrário:** Poucos testes falham, uma implantação é abortada, nossa equipe gastará um tempo precioso agora, temos um bug? Vamos investigar, oh não - parece que dois testes estavam modificando os mesmos dados iniciais -
Códigos de Exemplo @@ -932,7 +877,7 @@ Créditos:: { //adicionando dados de sites e administradores ao nosso banco de dados. Onde estão os dados? Do lado de fora. Em alguma estrutura json ou de migração externa @@ -951,6 +896,7 @@ it("When querying by site name, get the right site", async () => { }); ``` +
### :clap: Exemplo Fazendo Certo: Podemos permanecer dentro do teste, cada teste atua em seu próprio conjunto de dados @@ -977,12 +923,10 @@ it("When updating site name, get successful confirmation", async () => { :white_check_mark: **Faça:** Ao focar no teste da lógica dos componentes, os detalhes da interface do usuário se tornam um ruído que deve ser extraído, para que seus testes possam se concentrar em dados puros. Na prática, extraia os dados desejados da marcação de uma maneira abstrata que não seja muito acoplada à implementação gráfica, afirme apenas dados puros (vs detalhes gráficos de HTML/CSS) e desative animações que diminuem a velocidade. Você pode cair na tentação de evitar renderizar e testar apenas a parte de trás da interface do usuário (por exemplo, serviços, ações, armazenamento), mas isso resultará em testes fictícios que não se assemelham à realidade e não revelam casos em que os dados corretos nem chegam na interface do usuário -
❌ **Caso contrário:** Os dados puramente calculados do seu teste podem estar prontos em 10 ms, mas o teste inteiro durará 500 ms (100 testes = 1 min) devido a alguma animação sofisticada e irrelevante -
Códigos de Exemplo @@ -1017,6 +961,7 @@ test('When users-list is flagged to show only VIP, should display only VIP membe
### :thumbsdown: Exemplo Anti-padrão: Afirmações misturam detalhes da UI e dados + ```javascript test('When flagging to show only VIP, should display only VIP members', () => { // Arrange @@ -1036,12 +981,8 @@ test('When flagging to show only VIP, should display only VIP members', () => {
- - -

- ## ⚪ ️ 3.2 Consultar elementos HTML com base em atributos que provavelmente não serão alterados :white_check_mark: **Faça*:** Consulte elementos HTML com base em atributos que provavelmente sobreviverão a alterações gráficas, diferentemente dos seletores CSS e sim como os rótulos de formulário. Se o elemento designado não tiver esses atributos, crie um atributo dedicado a teste como 'test-id-submit-button'. Seguir essa rota não apenas garante que seus testes funcionais/lógicos nunca sejam quebrados devido a alterações de aparência, mas também fica claro para toda a equipe que esse elemento e atributo são utilizados por testes e não devem ser removidos @@ -1060,7 +1001,7 @@ test('When flagging to show only VIP, should display only VIP members', () => { ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20React-blue.svg "Exemplos com React") - + ```html // the markup code (part of React component)

@@ -1087,6 +1028,7 @@ test('When flagging to show only VIP, should display only VIP members', () => {
### :thumbsdown: Exemplo Anti-padrão: Confiando em atributos CSS + ```html {value} @@ -1101,12 +1043,8 @@ test('Whenever no data is passed, error metric shows zero', () => { }); ``` -

- - -
## ⚪ ️ 3.3 Sempre que possível, teste com um componente realista e totalmente renderizado @@ -1119,7 +1057,6 @@ Com tudo isso dito, uma palavra de cautela é necessária: essa técnica funcion ❌ **Caso contrário:** Ao entrar no interno de um componente, invocando seus métodos privados e verificando o estado interno - você teria que refatorar todos os testes ao refatorar a implementação dos componentes. Você realmente tem capacidade para esse nível de manutenção? -
Códigos de Exemplo @@ -1131,7 +1068,7 @@ Com tudo isso dito, uma palavra de cautela é necessária: essa técnica funcion ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20React-blue.svg "Exemplos com React") ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20Enzyme-blue.svg "Exemplos com Enzyme") - + ```javascript class Calendar extends React.Component { static defaultProps = {showFilters: false} @@ -1163,6 +1100,7 @@ test('Realistic approach: When clicked to show filters, filters are displayed', ``` ### :thumbsdown: Exemplo Anti-padrão: Simulando a realidade com renderização superficial + ```javascript test('Shallow/mocked approach: When clicked to show filters, filters are displayed', () => { @@ -1184,15 +1122,13 @@ test('Shallow/mocked approach: When clicked to show filters, filters are display
- ## ⚪ ️ 3.4 Não durma, use o suporte incorporado de frameworks para eventos assíncronos. Também tente acelerar as coisas -:white_check_mark: **Faça:** Em muitos casos, o tempo de conclusão da unidade em teste é desconhecido (por exemplo, a animação suspende a aparência do elemento) - nesse caso, evite dormir (por exemplo, setTimeOut) e prefira métodos mais determinísticos que a maioria das plataformas fornece. Algumas bibliotecas permitem aguardar operações (por exemplo, [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), outras fornecem API para esperar como [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Às vezes, uma maneira mais elegante é esboçar o recurso lento, como a API, por exemplo, e depois que o momento da resposta se torna determinístico, o componente pode ser explicitamente renderizado novamente. Quando, dependendo de algum componente externo que dorme, pode ser útil [apressar o relógio](https://jestjs.io/docs/en/timer-mocks). Dormir é um padrão a ser evitado, porque força o teste a ser lento ou arriscado (ao esperar por um período muito curto). Sempre que dormir e pesquisar for inevitável e não há suporte do framework de teste, algumas bibliotecas do NPM, como [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) podem ajudar com uma solução semi-determinística +:white_check_mark: **Faça:** Em muitos casos, o tempo de conclusão da unidade em teste é desconhecido (por exemplo, a animação suspende a aparência do elemento) - nesse caso, evite dormir (por exemplo, setTimeOut) e prefira métodos mais determinísticos que a maioria das plataformas fornece. Algumas bibliotecas permitem aguardar operações (por exemplo, [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), outras fornecem API para esperar como [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Às vezes, uma maneira mais elegante é esboçar o recurso lento, como a API, por exemplo, e depois que o momento da resposta se torna determinístico, o componente pode ser explicitamente renderizado novamente. Quando, dependendo de algum componente externo que dorme, pode ser útil [apressar o relógio](https://jestjs.io/docs/en/timer-mocks). Dormir é um padrão a ser evitado, porque força o teste a ser lento ou arriscado (ao esperar por um período muito curto). Sempre que dormir e pesquisar for inevitável e não há suporte do framework de teste, algumas bibliotecas do NPM, como [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) podem ajudar com uma solução semi-determinística
❌ **Caso contrário:** Ao dormir por um longo tempo, os testes serão uma ordem de magnitude mais lenta. Ao tentar dormir por pequenos números, o teste falha quando a unidade em teste não responde em tempo hábil. Portanto, tudo se resume a uma troca entre descamação e mau desempenho -
Códigos de Exemplo @@ -1233,6 +1169,7 @@ test('movie title appears', async () => { ``` ### :thumbsdown: Exemplo Anti-padrão: código de suspensão personalizado + ```javascript test('movie title appears', async () => { @@ -1256,7 +1193,6 @@ test('movie title appears', async () => {
-
## ⚪ ️ 3.5 Veja como o conteúdo é servido na rede @@ -1278,10 +1214,8 @@ test('movie title appears', async () => { ![](/assets/lighthouse2.png "Relatório de inspeção de carregamento de página do Lighthouse") -
-
## ⚪ ️ 3.6 Esboce recursos escamosos e lentos, como APIs de backend @@ -1292,7 +1226,6 @@ test('movie title appears', async () => { ❌ **Caso contrário:** Um teste médio é executado em não mais do que alguns ms, uma chamada típica da API dura 100ms>, isso torna cada teste ~ 20x mais lento -
Códigos de Exemplo @@ -1300,10 +1233,11 @@ test('movie title appears', async () => {
### :clap: Exemplo Fazendo Certo: fazendo o esboço ou interceptando chamadas de API + ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20React-blue.svg "Exemplos com React") ![](https://img.shields.io/badge/🔧%20Exemplo%20usando%20React%20Testing%20Library.svg "Exemplos com react-testing-library") - + ```javascript // unit under test @@ -1399,9 +1333,6 @@ beforeEach(setUser => () {
- - -
## ⚪ ️ 3.9 Faça um teste de fumaça E2E que viaja pelo mapa do site @@ -1412,7 +1343,6 @@ beforeEach(setUser => () { ❌ **Caso contrário:** Tudo pode parecer perfeito, todos os testes são aprovados, a verificação de integridade da produção também é positiva, mas o componente Payment teve algum problema de embalagem e apenas a rota /Payment não está sendo processada -
Códigos de Exemplo @@ -1420,8 +1350,10 @@ beforeEach(setUser => () {
### :clap: Exemplo Fazendo Certo: Fumaça viajando por todas as páginas + ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + ```javascript it('When doing smoke testing over all page, should load them all successfully', () => { // exemplified using Cypress but can be implemented easily @@ -1437,7 +1369,6 @@ it('When doing smoke testing over all page, should load them all successfully',
-
## ⚪ ️ 3.10 Expor os testes como um documento colaborativo vivo @@ -1446,7 +1377,6 @@ it('When doing smoke testing over all page, should load them all successfully', ❌ **Otherwise:** Depois de investir muitos recursos em testes, é uma pena não alavancar esse investimento e obter grande valor -
Códigos de Exemplo @@ -1456,6 +1386,7 @@ it('When doing smoke testing over all page, should load them all successfully', ### :clap: Exemplo Fazendo Certo: Descrevendo testes em linguagem humana usando cucumber-js ![](https://img.shields.io/badge/🔨%20Exemplo%20usando%20Cucumber-blue.svg "Exemplos usando Cucumber") + ```javascript // this is how one can describe tests using cucumber: plain language that allows anyone to understand and collaborate @@ -1474,26 +1405,23 @@ Feature: Twitter new tweet ``` ### :clap: Exemplo Fazendo Certo: Visualizando nossos componentes, seus vários estados e entradas usando o Storybook + ![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Usando StoryBook") ![alt text](assets/story-book.jpg "Storybook") -


- ## ⚪ ️ 3.11 Detecte problemas visuais com ferramentas automatizadas - :white_check_mark: **Faça:** Configure ferramentas automatizadas para capturar a tela da interface do usuário quando alterações forem apresentadas e detectar problemas visuais, como sobreposição ou quebra de conteúdo. Isso garante que não apenas os dados corretos sejam preparados, mas também que o usuário possa vê-los convenientemente. Essa técnica não é amplamente adotada, nossa mentalidade de teste se inclina para testes funcionais, mas é o visual que o usuário experimenta e, com tantos tipos de dispositivos, é muito fácil ignorar alguns erros desagradáveis ​​da interface do usuário. Algumas ferramentas gratuitas podem fornecer o básico - gerar e salvar capturas de tela para a inspeção dos olhos humanos. Embora essa abordagem possa ser suficiente para aplicativos pequenos, ela é falha como qualquer outro teste manual que exige mão de obra humana sempre que algo muda. Por outro lado, é bastante desafiador detectar problemas de interface do usuário automaticamente devido à falta de definição clara - é aqui que o campo de 'Regressão Visual' entra em cena e resolve esse quebra-cabeça comparando a interface antiga com as alterações mais recentes e detectando diferenças. Algumas ferramentas OSS/gratuitas podem fornecer algumas dessas funcionalidades (por exemplo, [wraith](https://github.com/BBC-News/wraith), [PhantomCSS]([https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)) mas pode cobrar um tempo significativo de configuração. A linha comercial de ferramentas (por exemplo [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) dá um passo adiante ao suavizar a instalação e incluir recursos avançados, como interface de gerenciamento, alerta, captura inteligente, eliminando o 'ruído visual' (por exemplo, anúncios, animações) e até mesmo a análise de causa raiz das alterações no DOM/css que levaram ao problema
❌ **Caso contrário:** Quão boa é uma página de conteúdo que exibe ótimo conteúdo (100% nos testes aprovados), carrega instantaneamente, mas metade da área de conteúdo está oculta? -
Códigos de Exemplo @@ -1506,7 +1434,6 @@ Feature: Twitter new tweet
- ### :clap: Exemplo Fazendo Certo: Configurando o wraith para capturar e comparar instantâneos da UI ![](https://img.shields.io/badge/🔨%20Exemplo%20usando%20Wraith-blue.svg @@ -1563,16 +1490,10 @@ describe('visual validation', () => { }); ``` - - -
- -

- # Seção 4️⃣: Medindo a Eficácia dos Testes

@@ -1585,10 +1506,8 @@ Dicas de implementação: Convém configurar sua integração contínua (CI) par
- ❌ **Caso contrário:** Confiança e números andam de mãos dadas, sem realmente saber que você testou a maior parte do sistema - haverá também algum medo. e o medo vai atrasá-lo -
Códigos de Exemplo @@ -1596,6 +1515,7 @@ Dicas de implementação: Convém configurar sua integração contínua (CI) par
### :clap: Exemplo: um relatório de cobertura típico + ![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "Um relatório de cobertura típico")
@@ -1609,8 +1529,6 @@ Dicas de implementação: Convém configurar sua integração contínua (CI) par
- -

## ⚪ ️ 4.2 Inspecionar relatórios de cobertura para detectar áreas não testadas e outras esquisitices @@ -1618,10 +1536,8 @@ Dicas de implementação: Convém configurar sua integração contínua (CI) par :white_check_mark: **Faça:** Alguns problemas se escondem logo abaixo do radar e são realmente difíceis de encontrar usando ferramentas tradicionais. Esses não são realmente erros, mas um comportamento surpreendente do aplicativo que pode ter um impacto grave. Por exemplo, geralmente algumas áreas de código nunca ou raramente são invocadas — você pensou que a classe 'PricingCalculator' está sempre definindo o preço do produto, mas, na verdade, nunca é invocada, embora tenhamos 10000 produtos no banco de dados e muitas vendas... Os relatórios de cobertura de código ajudam a perceber se o aplicativo se comporta da maneira que você acredita. Além disso, ele também pode destacar quais tipos de código não foram testados—ser informado que 80% do código é testado não informa se as partes críticas estão cobertas. Gerar relatórios é fácil—basta executar seu aplicativo em produção ou durante o teste com rastreamento de cobertura e ver relatórios coloridos que destacam a frequência com que cada área de código é invocada. Se você dedicar um tempo para vislumbrar esses dados—poderá encontrar algumas pegadinhas
- ❌ **Caso contrário:** Se você não sabe quais partes do seu código são deixadas sem teste, não sabe de onde os problemas podem surgir -
Códigos de Exemplo @@ -1636,7 +1552,6 @@ Com base em um cenário do mundo real, onde rastreamos o uso de nossos aplicativ
-

## ⚪ ️ 4.3 Meça a cobertura lógica usando teste de mutação @@ -1652,7 +1567,6 @@ O teste baseado em mutação está aqui para ajudar, medindo a quantidade de có Saber que todas ou a maioria das mutações foram mortas dá uma confiança muito maior do que a cobertura tradicional e o tempo de instalação é semelhante
- ❌ **Caso contrário:** Você ficará enganado ao acreditar que 85% de cobertura significa que seu teste detectará bugs em 85% do seu código
@@ -1665,6 +1579,7 @@ Saber que todas ou a maioria das mutações foram mortas dá uma confiança muit ![](https://img.shields.io/badge/🔨%20Exemplo%20usando%20Stryker-blue.svg "Usando Stryker") + ```javascript function addNewOrder(newOrder) { logger.log(`Adding new order ${newOrder}`); @@ -1679,6 +1594,7 @@ it("Test addNewOrder, don't use such test names", () => { });//Triggers 100% code coverage, but it doesn't check anything ``` +
### :clap: Exemplo Fazendo Certo: Stryker reports, uma ferramenta para teste de mutação, detecta e conta a quantidade de código que não foi testado (mutações) @@ -1687,8 +1603,6 @@ it("Test addNewOrder, don't use such test names", () => {
- -

## ⚪ ️4.4 Impedindo problemas de código de teste com os linters de teste @@ -1697,10 +1611,8 @@ it("Test addNewOrder, don't use such test names", () => {
- ❌ **Caso contrário:** Ver 90% de cobertura de código e 100% de testes verdes fará com que seu rosto seja um grande sorriso apenas até você perceber que muitos testes não afirmam nada e que muitos conjuntos de testes foram ignorados. Tomara que você não tenha implantado nada com base nessa observação falsa -
Códigos de Exemplo @@ -1726,7 +1638,6 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test

- # Seção 5️⃣: IC e Outras Medidas de Qualidade

@@ -1736,10 +1647,8 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test :white_check_mark: **Faça:** Linters são um almoço grátis, com 5 minutos de configuração, você obtém gratuitamente um piloto automático que protege seu código e captura de problemas significativos enquanto digita. Já se foram os dias em que linting era apenas por beleza (sem ponto e vírgula!). Hoje em dia, Linters podem detectar problemas graves, como erros que não são lançados corretamente e perda de informações. Além do seu conjunto básico de regras (como [ESLint padrão](https://www.npmjs.com/package/eslint-plugin-standard) ou [estilo Airbnb](https://www.npmjs.com/package/eslint-config-airbnb)), considere incluir alguns Linters especializados como [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) que pode descobrir testes sem asserções, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) pode descobrir promessas sem resolução (seu código nunca vai continuar), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) que pode descobrir expressões regulares inseguras que podem ser usadas para ataques do DOS e[eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) é capaz de alarmar quando o código usa métodos da biblioteca de utilitários que fazem parte dos métodos principais do V8, como Lodash._map(…)
- ❌ **Caso Contrário:** Considere um dia chuvoso em que sua produção continua travando, mas os logs não exibem o rastreamento do stack de erros. O que aconteceu? Seu código lançou um objeto sem erro por engano e o rastreamento do stack foi perdido, uma boa razão para bater a cabeça contra uma parede de tijolos. Uma configuração de linter de 5 minutos pode detectar esse erro de DIGITAÇÃO e salvar seu dia -
Códigos de Exemplo @@ -1747,13 +1656,11 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test
### :thumbsdown: Exemplo Anti-padrão: O objeto sem a propriedade erro é lançado por engano, nenhum rastreamento do stack será exibido para esse erro. Felizmente, o ESLint capta o próximo bug de produção + ![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "O objeto sem a propriedade erro é lançado por engano, nenhum rastreamento do stack será exibido para esse erro. Felizmente, o ESLint capta o próximo bug de produção")
- - -

# ⚪ ️ 5.2 Encurte o ciclo de feedback com o IC de desenvolvedor local @@ -1763,10 +1670,8 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test Na prática alguns fornecedores de IC (exemplo: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) permitir a execução do pipeline localmente. Algumas ferramentas comerciais como [wallaby fornece informações valiosas e intuições de teste](https://wallabyjs.com/) como um protótipo de desenvolvedor (sem afiliação). Como alternativa, você pode apenas adicionar um npm script no package.json que executa todos os comandos de qualidade (por exemplo teste, lint, vulnerabilidades) — use ferramentas como [concurrently](https://www.npmjs.com/package/concurrently) para paralelismo e código de saída diferente de zero, se uma das ferramentas falhar. Agora o desenvolvedor deve apenas chamar um comando— por exemplo ‘npm run quality’ — para obter feedback instantâneo. Considere também abortar um commit se a verificação de qualidade falhar usando um githook ([husky pode ajudar](https://github.com/typicode/husky))
- ❌ **Caso Contrário:** Quando os resultados da qualidade chegam no dia seguinte ao código, o teste não se torna uma parte fluente do desenvolvimento, e sim um artefato formal após o fato -
Códigos de Exemplo @@ -1774,6 +1679,7 @@ Na prática alguns fornecedores de IC (exemplo: [CircleCI local CLI](https://cir
### :clap: Exemplo Fazendo Certo: npm scripts que realizam inspeção de qualidade de código, todos são executados em paralelo sob demanda ou quando um desenvolvedor está tentando enviar um novo código + ```javascript "scripts": { "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"", @@ -1795,9 +1701,6 @@ Na prática alguns fornecedores de IC (exemplo: [CircleCI local CLI](https://cir
- - -

# ⚪ ️5.3 Realize testes e2eem um verdadeiro espelho de produção @@ -1807,10 +1710,8 @@ Na prática alguns fornecedores de IC (exemplo: [CircleCI local CLI](https://cir O enorme ecossistema Kubernetes ainda não formalizou uma ferramenta conveniente padrão para espelhamento local e de IC, embora muitas novas ferramentas sejam lançadas com frequência. Uma abordagem é executar ‘minimized-Kubernetes’ usando ferramentas como [Minikube](https://kubernetes.io/docs/setup/minikube/) e [MicroK8s](https://microk8s.io/) que se assemelham-se à coisa real só vêm com menos sobrecarga. Outra abordagem é testar em um ambiente remoto ‘real-Kubernetes’, alguns provedores de IC (por exemplo, [Codefresh](https://codefresh.io/)) possuem integração nativa com ambiente Kubernetes e facilitam a execução do pipeline do IC sobre o ambiente real, outros permitem scripts personalizados em um Kubernetes remoto.
- ❌ **Caso Contrário:** O uso de tecnologias diferentes para demandas de produção e teste mantém dois modelos de implantação e mantém os desenvolvedores e a equipe de operações separados -
Códigos de Exemplo @@ -1823,19 +1724,14 @@ O enorme ecossistema Kubernetes ainda não formalizou uma ferramenta conveniente
- - - -

## ⚪ ️5.4 Paralelizar a execução do teste -:white_check_mark: **Faça:** Quando bem feito, o teste é seu amigo 24/7, fornecendo feedback quase instantâneo. Na prática, a execução de 500 testes de unidade limitados à CPU em um único thread pode levar muito tempo. Felizmente, executores de teste modernos e plataformas de IC (como [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) e [extenções Mocha](https://github.com/yandex/mocha-parallel-tests)) podem paralelizar os testes em vários processos e obter uma melhoria significativa no tempo de feedback. Alguns fornecedores de IC também paralelam testes entre contêineres (!) o que reduz ainda mais o ciclo de feedback. Seja localmente em vários processos ou em alguma ILC na nuvem usando várias máquinas— paralelizando a demanda, mantendo os testes autônomos, pois cada um pode ser executado em diferentes processos +:white_check_mark: **Faça:** Quando bem feito, o teste é seu amigo 24/7, fornecendo feedback quase instantâneo. Na prática, a execução de 500 testes de unidade limitados à CPU em um único thread pode levar muito tempo. Felizmente, executores de teste modernos e plataformas de IC (como [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) e [extenções Mocha](https://github.com/yandex/mocha-parallel-tests)) podem paralelizar os testes em vários processos e obter uma melhoria significativa no tempo de feedback. Alguns fornecedores de IC também paralelam testes entre contêineres (!) o que reduz ainda mais o ciclo de feedback. Seja localmente em vários processos ou em alguma ILC na nuvem usando várias máquinas— paralelizando a demanda, mantendo os testes autônomos, pois cada um pode ser executado em diferentes processos ❌ **Caso Contrário:** Obter resultados de testes 1 hora após o envio do novo código, enquanto você codifica os próximos recursos, é uma ótima receita para tornar os testes menos relevantes -
Códigos de Exemplo @@ -1843,28 +1739,27 @@ O enorme ecossistema Kubernetes ainda não formalizou uma ferramenta conveniente
### :clap: Exemplo Fazendo Certo: Mocha parallel & Jest superam facilmente o Mocha tradicional graças ao teste de paralelização ([Créditos: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) + ![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest superam facilmente o Mocha tradicional graças ao teste de paralelização (Créditos: JavaScript Test-Runners Benchmark)")
- - -

## ⚪ ️5.5 Fique longe de questões legais usando licença e verificação de plágio + :white_check_mark: **Faça:** Problemas de licenciamento e plágio provavelmente não são sua principal preocupação no momento, mas por que não resolver isso também em 10 minutos? Um monte de pacotes npm como [license check](https://www.npmjs.com/package/license-checker) e [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (comercial com plano gratuito) podem ser facilmente incorporado ao seu pipeline de IC e inspecionar problemas, como dependências com licenças restritivas ou código que foi copiado e colado do Stackoverflow e aparentemente viola alguns direitos autorais ❌ **Caso Contrário:** Involuntariamente, os desenvolvedores podem usar pacotes com licenças inadequadas ou copiar e colar código comercial e enfrentar problemas legais -
Códigos de Exemplo
-### :clap: Exemplo Fazendo Certo: +### :clap: Exemplo Fazendo Certo + ```javascript //instale license-checker no seu ambiente IC ou também localmente npm install -g license-checker @@ -1878,19 +1773,16 @@ license-checker --summary --failOn BSD ![alt text](assets/bp-25-nodejs-licsense.png) -
- -

## ⚪ ️5.6 Inspecionar constantemente as dependências vulneráveis + :white_check_mark: **Faça:** Mesmo as dependências mais respeitáveis, como o Express, têm vulnerabilidades conhecidas. Isso pode ser facilmente domado usando ferramentas da comunidade, como [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), ou ferramentas comerciais como [snyk](https://snyk.io/) (oferece também uma versão comunitária gratuita). Ambos podem ser chamados a partir do seu IC em cada build ❌ **Caso Contrário:** Para manter seu código livre de vulnerabilidades sem ferramentas dedicadas, é necessário seguir constantemente as publicações on-line sobre novas ameaças. Bastante tedioso -
Códigos de Exemplos @@ -1898,16 +1790,15 @@ license-checker --summary --failOn BSD
### :clap: Exemplo: Resultado de NPM Audit + ![alt text](assets/bp-26-npm-audit-snyk.png "Resultado de NPM Audit")
- - -

## ⚪ ️5.7 Automatize atualizações de dependência + :white_check_mark: **Faça:** Yarn e npm recentemente incluiram package-lock.json que introduziu um sério desafio (o caminho para o inferno é pavimentado com boas intenções) — por padrão agora, os pacotes não estão mais recebendo atualizações. Mesmo uma equipe executando muitas implantações novas com ‘npm install’ & ‘npm update’ não receberão novas atualizações. Isso leva a versões abaixo dos pacotes de dependência, na melhor das hipóteses, ou ao código vulnerável, na pior das hipóteses. As equipes agora contam com a boa vontade e a memória dos desenvolvedores para atualizar manualmente o package.json ou usar ferramentas [como ncu](https://www.npmjs.com/package/npm-check-updates) manualmente. Uma maneira mais confiável seria automatizar o processo de obtenção das versões de dependência mais confiáveis, embora não haja uma solução certeira ainda, existem duas vias de automação possíveis: (1) O IC pode falhar nas construções que possuem dependências obsoletas — usando ferramentas como [‘npm outdated’](https://docs.npmjs.com/cli/outdated) ou ‘npm-check-updates (ncu)’ . Fazer isso forçará os desenvolvedores a atualizar dependências. @@ -1917,10 +1808,8 @@ license-checker --summary --failOn BSD Uma política de atualização eficiente pode permitir um ‘período de acomodação’ — deixe o código ficar atrás do @latest por algum tempo e versões antes de considerar a cópia local como obsoleta (por exemplo. versão local é 1.3.1 e a versão do repositório é 1.3.8)
- ❌ **Caso Contrário:** Sua produção executará pacotes que foram explicitamente marcados pelo autor como arriscados -
Códigos de Exemplo @@ -1928,33 +1817,31 @@ Uma política de atualização eficiente pode permitir um ‘período de acomoda
### :clap: Exemplo: [ncu](https://www.npmjs.com/package/npm-check-updates) pode ser usado manualmente ou em um pipeline de IC para detectar quanto o código está atrasado em relação às versões mais recentes -![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu pode ser usado manualmente ou em um pipeline de IC para detectar quanto o código está atrasado em relação às versões mais recentes") +![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu pode ser usado manualmente ou em um pipeline de IC para detectar quanto o código está atrasado em relação às versões mais recentes")
-

## ⚪ ️ 5.8 Outras dicas de IC não relacionadas ao Node + :white_check_mark: **Faça:** Esta postagem é focada em conselhos de teste relacionados ou pelo menos podem ser exemplificados com o Node JS. Este marcador, no entanto, agrupa algumas dicas não relacionadas ao nó que são bem conhecidas
  1. Use uma sintaxe declarativa. Essa é a única opção para a maioria dos fornecedores, mas as versões mais antigas do Jenkins permitem o uso de código ou interface do usuário.
  2. Opte por um fornecedor que tenha suporte nativo ao Docker
  3. Falhe cedo, execute seus testes mais rápidos primeiro. Crie uma etapa/meta de "Teste de fumaça" que agrupe várias inspeções rápidas (por exemplo linting, testes unitários) e fornecer feedback instantâneo para o responsável pelo código
  4. Facilite a varredura de todos os artefatos de construção, incluindo relatórios de teste, relatórios de cobertura, relatórios de mutação, logs, etc.
  5. Crie vários pipelines/trabalhos para cada evento, reutilize as etapas entre eles. Por exemplo, configure um trabalho para commits de branches de recursos e outro para PR na master. Permita que cada uma reutilize a lógica usando etapas compartilhadas (a maioria dos fornecedores fornece algum mecanismo para reutilização de código)
  6. Nunca incorpore segredos em uma declaração de trabalho, pegue-os em um armazenamento secreto ou na configuração do trabalho
  7. Explicitamente aumente a versão em uma compilação de versão ou pelo menos garanta que o desenvolvedor o fez
  8. Compileapenas uma vez e execute todas as inspeções no artefato de construção único (por exemplo, imagem do Docker)
  9. Teste em um ambiente efêmero que não varia de estado entre compilações. Armazenar em cache node_modules pode ser a única exceção

- ❌ **Caso Contrário:** Você perderá anos de sabedoria

## ⚪ ️ 5.9 Matriz de construção: execute as mesmas etapas de IC usando várias versões do Node + :white_check_mark: **Faça:** A verificação da qualidade é sobre acaso, quanto mais você cobrir, mais sorte terá na detecção de problemas mais cedo. Ao desenvolver pacotes reutilizáveis ​​ou executar uma produção de vários clientes com várias configurações e versões do Node, o IC deve executar o pipeline de testes em todas as permutações de configurações. Por exemplo, supondo que usamos o MySQL para alguns clientes e o Postgres para outros — alguns fornecedores de IC suportam um recurso chamado "Matriz" que permitem executar o processo de teste contra todas as permutações do MySQL, Postgres e várias versões do Node, como 8, 9 e 10. Isso é feito usando a configuração apenas sem nenhum esforço adicional (supondo que você tenha testes ou quaisquer outras verificações de qualidade). Outros ICs que não suportam Matrix podem ter extensões ou ajustes para permitir isso
- ❌ **Caso Contrário:** Então, depois de fazer todo esse trabalho duro de escrever testes, vamos permitir que os bugs entrem apenas por causa de problemas de configuração? -
Códigos de Exemplo @@ -1962,6 +1849,7 @@ Uma política de atualização eficiente pode permitir um ‘período de acomoda
### :clap: Exemplo: Usando a definição de construção do Travis (fornecedor de IC) para executar o mesmo teste em várias versões do Node +
language: node_js
node_js:
- "7"
- "6"
- "5"
- "4"
install:
- npm install
script:
- npm run test
@@ -1969,8 +1857,6 @@ Uma política de atualização eficiente pode permitir um ‘período de acomoda # Time - - ## Yoni Goldberg
@@ -2019,6 +1905,7 @@ Teve o cuidado de revisar, melhorar, usar lint e polir todos os textos **Sobre:** Adora trabalhar em projetos Node.js. e segurança de aplicativos da web. ## Contribuidores ✨ + Agradecemos a essas pessoas maravilhosas que contribuíram para este repositório! diff --git a/readme-zh-CN.md b/readme-zh-CN.md index 1abaa83b..ceebeb51 100644 --- a/readme-zh-CN.md +++ b/readme-zh-CN.md @@ -7,26 +7,27 @@
## 📗 45+ 最佳实践:非常全面彻底 -这篇文章从 A 到 Z 给出了 JavaScript & Node.js 的稳定性指南。它为你整理总结了市面上大量的最佳博客文章、书籍以及工具。 +这篇文章从 A 到 Z 给出了 JavaScript & Node.js 的稳定性指南。它为你整理总结了市面上大量的最佳博客文章、书籍以及工具。 ## 🚢 进阶:在基础上前进 10000 公里 -从基础领域跨上前往进阶话题的旅程,包括:在生产环境测试、编译测试、基于属性的测试以及很多策略 & 专业工具。如果你仔细阅读了本指南中的每个字,则你的测试能力将有可能大大超过平均水平。 +从基础领域跨上前往进阶话题的旅程,包括:在生产环境测试、编译测试、基于属性的测试以及很多策略 & 专业工具。如果你仔细阅读了本指南中的每个字,则你的测试能力将有可能大大超过平均水平。 ## 🌐 全栈:前端、后端、CI、任何岗位 + 先了解通用的测试实践为其他应用层的打下基础。然后,在你自己的领域深入探索:前端/UI、后端、CI 甚至是他们所有的层面。
### 作者 Yoni Goldberg + - 一位 JavaScript & Node.js 顾问 - 👨‍🏫 [我的测试网站](https://www.testjavascript.com/) - 在欧洲 & 美国了解 [我的测试网站](https://www.testjavascript.com/) - [在 Twitter 关注我](https://twitter.com/goldbergyoni/) - 来 [LA](https://js.la/), [Verona](https://2019.nodejsday.it/), [Kharkiv](https://kharkivjs.org/), [free webinar](https://zoom.us/webinar/register/1015657064375/WN_Lzvnuv4oQJOYey2jXNqX6A)听我的演讲。后续工作待定。 - [我的 JavaScript 质量新闻](https://testjavascript.com/newsletter/) - 战略层面的视野和信息 -

## `内容列表` @@ -57,7 +58,6 @@ JS 领域的 CI 指南(9 条)

- # 第 0 章:黄金法则
@@ -78,7 +78,6 @@ JS 领域的 CI 指南(9 条) ### 准备好开始了吗? -

# 第一章: 测试剖析 @@ -97,7 +96,6 @@ JS 领域的 CI 指南(9 条)
- ❌ **否则:** 当一个名为“新增产品”的测试用例挂掉之后,你如何准确找到是哪里出问题了?
@@ -126,9 +124,11 @@ describe('Products Service', function() { }); ``` +
### :clap: 正例: 一个包含三部分的用例名 + ![alt text](/assets/bp-1-3-parts.jpeg "A test name that constitutes 3 parts")
@@ -145,10 +145,8 @@ describe('Products Service', function() { 3rd A - 断言(Assert):保证得到的值符合预期。通常一行代码。 -
- ❌ **否则:** 你不仅要花大量时间理解这段代码,而且本该是最简单的部分却耗费了你的大量脑细胞。
@@ -194,22 +192,15 @@ test('Should be classified as premium', () => { }); ``` -
- -

- - - ## ⚪ ️1.3 用产品语言描述期望:使用 BDD 形式的断言 :white_check_mark: **建议:** 使用声明的方式写代码,可以使读者无脑 get 到重点。而如果你的代码使用各种条件逻辑包裹起来,则会增加读者的理解难度。因此,我们应尽量使用类似人类语言的形式描述如 `expect` 或 `should` 而不是自己写代码。如果 Chai 和 Jest 不包含你想要的断言,而且这种断言可被高度复用时,你可以考虑 [扩展 Jest 匹配器 (Jest)](https://jestjs.io/docs/en/expect#expectextendmatchers) 或者写一个 [自定义 Chai 插件](https://www.chaijs.com/guide/plugins/)
- ❌ **否则:** 团队的测试代码会越写越少,而且会用 .skip() 把一些讨厌的测试用例注释掉。
@@ -220,7 +211,7 @@ test('Should be classified as premium', () => { "Examples with Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") - ### :thumbsdown: 反例: 为了了解该用例的目的,读者必须快速浏览冗长复杂的代码 +### :thumbsdown: 反例: 为了了解该用例的目的,读者必须快速浏览冗长复杂的代码 ```javascript test("When asking for an admin, ensure only ordered admins in results" , () => { @@ -247,11 +238,11 @@ test("When asking for an admin, ensure only ordered admins in results" , () => { }); ``` +
### :clap: 正例: 快速浏览下面的声明式用例很轻松 - ```javascript it("When asking for an admin, ensure only ordered admins in results" , () => { //assuming we've added here two admins @@ -265,16 +256,13 @@ it("When asking for an admin, ensure only ordered admins in results" , () => { -

- ## ⚪ ️ 1.4 坚持黑盒测试:只测 public 方法 :white_check_mark: **建议:** 测试内部逻辑是无意义且浪费时间的。如果你的 代码/API 返回了正确的结果,你真的需要花三个小时时间去测试它内部究竟如何实现的,并且在之后维护这一堆脆弱的测试吗?每当测试一个公共方法时,其私有实现也会被隐式地测试,只有当存在某个问题(例如错误的输出)时测试才会中断。这种方法也称为`行为测试`。另一方面,如果你测试内部方法(白盒方法)—你的关注点将从组件的输出结果转移到具体的细节上,如果某天内部逻辑改变了,即使结果依然正确,你也要花精力去维护之前的测试逻辑,这无形中增加了维护成本。
- ❌ **否则:** 你的代码将会像[狼来了](https://en.wikipedia.org/wiki/The_Boy_Who_Cried_Wolf)一样:总是叫唤着“出问题啦”(比如一个因私有变量名改变导致的用例失败)。则人们必然会开始忽略 CI 的通知,直到某天真正的 bug 被忽略……
@@ -312,9 +300,6 @@ it("White-box test: When the internal methods get 0 vat, it return 0 response", - - -

## ⚪ ️ ️1.5 使用正确的测试替身(Test Double):避免总用 stub 和 spy @@ -323,7 +308,6 @@ it("White-box test: When the internal methods get 0 vat, it return 0 response",
- ❌ **否则:** 任何代码重构都要求搜索代码中的所有 mock 并相应地进行更新。测试变成了一种负担,而不是一个帮手。
@@ -333,8 +317,10 @@ it("White-box test: When the internal methods get 0 vat, it return 0 response",
### :thumbsdown: 反例: 关注内部实现的 mock + ![](https://img.shields.io/badge/🔧%20Example%20using%20Sinon-blue.svg "Examples with Mocha & Chai") + ```javascript it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => { //Assume we already added a product @@ -345,6 +331,7 @@ it("When a valid product is about to be deleted, ensure data access DAL was call dataAccessMock.verify(); }); ``` +
### :clap:正例: 使用 spy 关注于测试需求本身,而作为副作用不得不接触内部 @@ -360,8 +347,6 @@ it("When a valid product is about to be deleted, ensure an email is sent", async - -

## ⚪ ️1.6 不要“foo”,使用真实数据 @@ -369,9 +354,7 @@ it("When a valid product is about to be deleted, ensure an email is sent", async :white_check_mark: **建议:** 生产环境中的 bug 通常是在一些特殊或者意外的输入下出现的——所以测试的输入数据越真实,越容易在早期抓住问题。使用现有的一些库(比如 [Faker](https://www.npmjs.com/package/faker))去造“假”真数据来模拟生产环境数据的多样性和形式。比如,这些库可以生成真实的电话号码、用户名、信用卡、公司名等等。你还可以创建一些测试(在单元测试之上,而不是替代)生产随机 fakers 数据来扩展你的测试单元,甚至从生产环境中导入真实的数据。想要进阶的话,请看下一条:基于属性的测试。
- -❌ **否则:** 你所有的用例都在 “foo” 之类的输入值下表现正确,结果上线后收到诸如  “[@3e2ddsf ]() . ##’ 1 fdsfds . fds432 AAAA” 之类的输入后挂掉了。 - +❌ **否则:** 你所有的用例都在 “foo” 之类的输入值下表现正确,结果上线后收到诸如  “[@3e2ddsf]() . ##’ 1 fdsfds . fds432 AAAA” 之类的输入后挂掉了。
@@ -384,7 +367,6 @@ it("When a valid product is about to be deleted, ensure an email is sent", async ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") - ```javascript const addProduct = (name, price) =>{ const productNameRegexNoSpace = /^\S*$/;//no white-space allowd @@ -405,6 +387,7 @@ test("Wrong: When adding new product with valid properties, get successful confi }); ``` +
### :clap:正例: 随机生成真实的输入数据 @@ -421,9 +404,6 @@ it("Better: When adding new valid product, get successful confirmation", async ( - - -

## ⚪ ️ 1.7 基于属性的测试:测试输入的多种组合 @@ -431,10 +411,8 @@ it("Better: When adding new valid product, get successful confirmation", async ( :white_check_mark: **建议:** 通常我们只会选择部分的数据样例去测试,即使是使用了上一节讲到的工具去模拟真实数据,我们也只覆盖到了一部分输入的组合(`method(‘’, true, 1), method(“string” , false” , 0)`)。然而在生产环境中,一个拥有 5 个参数的 API,可能会遇到上千种排列组合,而其中的某一种可能会把你的进程搞挂([见 Fuzz Testing](https://en.wikipedia.org/wiki/Fuzzing))。如何自动生成这上千种组合并在它们出问题后 catch 到?基于属性的测试适用于这种需求:向你的测试单元传入所有可能的输入组合,以增加发现 bug 的可能。例如,给定一个方法 —— `addNewProduct(id, name, isDiscount)`,支持属性测试的库将使用一批`(number, string, boolean)`组合调用此方法,比如`(1,“iPhone”,false)`,`(2,“Galaxy”,true)`。您可以使用您最喜欢的测试运行器(Mocha、Jest等),
通常,我们为每个测试选择一些输入样本。即使输入格式类似于现实世界的数据(见子弹“别foo”),我们只涉及几个输入组合(方法(“,真的,1),方法(“字符串”,假”,0)),然而,在生产中,一个API调用与成千上万的5个参数可以调用不同的排列,其中一个可能使我们的流程(见模糊测试)。如果您可以编写一个测试,自动发送1000个不同输入的排列组合,并捕获我们的代码未能返回正确响应的输入,那该怎么办?基于属性的测试就是这样一种技术:通过发送所有可能的输入组合到你的测试单元中,它增加了发现bug的偶然性。例如,给定一个方法—addNewProduct(id, name, isDiscount)—支持库将使用许多(number, string, boolean)组合调用此方法,比如(1,“iPhone”,false),(2,“Galaxy”,true)。您可以使用您最喜欢的测试运行器(Mocha、Jest等):比如 [js-verify](https://github.com/jsverify/jsverify) 或者 [testcheck](https://github.com/leebyron/testcheck-js) (文档比较好)。 更新: Nicolas Dubien 在下面的回复中建议 [了解下 fast-check](https://github.com/dubzzz/fast-check#readme) 它提供了更多的能力,似乎更易维护。
- ❌ **否则:** 你无意中选择的输入数据只覆盖了没问题的代码路径。不幸的是,它没有真正发现了 bug。 -
代码示例 @@ -464,9 +442,6 @@ describe("Product service", () => {
- - -

## ⚪ ️ 1.8 snapshot:如果需要,仅使用短的行内快照 @@ -511,9 +486,11 @@ expect(receivedPage).toMatchSnapshot(); }); ``` +
### :clap: 正例: 期望是可见且集中的 + ```javascript it('When visiting TestJavaScript.com home page, a menu is displayed', () => { //Arrange @@ -538,7 +515,6 @@ expect(menu).toMatchInlineSnapshot(` -

## ⚪ ️1.9 不要写全局的 fixtures 和 seeds,而是放在每个测试中 @@ -546,10 +522,8 @@ expect(menu).toMatchInlineSnapshot(` :white_check_mark: **建议:** 参照黄金法则,每条测试需要在它自己的 DB 行中运行避免互相污染。现实中,这条规则经常被打破:为了性能提升而在执行测试前全局初始化数据库([也被称为‘test fixture’](https://en.wikipedia.org/wiki/Test_fixture))。尽管性能很重要,但是它可以通过后面讲的「分组件测试」缓和。为了减轻复杂度,我们可以在每个测试中只初始化自己需要的数据。除非性能问题真的非常显著,那么可以做一定的妥协——仅在全局放不会改变的数据(比如 query)。
- ❌ **否则:** 一部分测试挂了,我们的团队花费大量宝贵时间后发现,是由于两个测试同时改变了同一个 seed 数据导致的。 -
代码示例 @@ -579,6 +553,7 @@ it("When querying by site name, get the right site", async () => { }); ``` +
### :clap: 正例: 每个用例操作它自己的数据集 @@ -599,19 +574,17 @@ it("When updating site name, get successful confirmation", async () => {
-
## ⚪ ️ 1.10 不要 catch 错误,expect 它们 + :white_check_mark: **建议:** 当你测试一些输入是否会触发错误时,使用 try-catch-finally 测试看起来似乎没问题。但结果会比较奇葩(会隐藏测试的意图和期望结果),并且把 tc 复杂化(比如下面的例子)。 一个更优雅的替代方法是使用 Chai断言 `expect(method).to.throw` (或者 Jest 的: `expect(method).toThrow()`)。必须保证异常包含一个表示错误类型的属性,否则如果只给出一个通用错误,应用程序没法展示足够的信息。
- ❌ **否则:** 从测试报告(如 CI 报告)中查找出错的位置将会很痛苦。 -
代码示例 @@ -638,6 +611,7 @@ expect(errorWeExceptFor).not.to.be.null; }); ``` +
### :clap: 正例: 一个人类可读的期望,它很容易被理解,甚至可被 QA 或技术 PM 理解 @@ -651,9 +625,6 @@ it.only("When no product name, it throws error 400", async() => {
- - -

## ⚪ ️ 1.11 为你的测试用例打标签 @@ -661,10 +632,8 @@ it.only("When no product name, it throws error 400", async() => { :white_check_mark: **建议:** 不同的测试需要在不同的场景中执行:快速冒烟、IO 测试、开发者保存或者提交文件后的测试、当一个新的 PR 提交后需要全量执行的端到端测试 等等。你可以用一些 #cold #api #sanity 之类的标签标注测试来达到这个目的,这样你就可以在测试时仅测试想要的子集。如在 mocha 中可以这样唤起用例组 `mocha — grep ‘sanity’` 。
- ❌ **否则:** 执行所有的用例,包括执行大量 DB 查询的用例,开发者做的任何小改动都需要等待很长的时间,将会导致开发者不再想运行测试。 -
代码示例 @@ -675,6 +644,7 @@ it.only("When no product name, it throws error 400", async() => { ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + ```javascript //this test is fast (no DB) and we're tagging it correspondigly //now the user/CI can run it frequently @@ -691,9 +661,6 @@ describe('Order service', function() {
- - -

## ⚪ ️1.12 其他常见的优秀测试习惯 @@ -706,7 +673,6 @@ describe('Order service', function() {

- # 第二章: 后端测试 ## ⚪ ️2.1 丰富您的测试组合:不局限于单元测试和测试金字塔 @@ -721,10 +687,8 @@ describe('Order service', function() {
- ❌ **否则:** 你将错过一些超高投入产出比的工具,比如 Fuzz、lint、mutation 这些工具只需 10 分钟配置就能贡献价值。 -
代码示例 @@ -732,6 +696,7 @@ describe('Order service', function() {
### :clap: 正例: Cindy Sridharan 在她的文章“测试微服务——理智的方式”中提出了一个丰富的测试组合 + ![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") ☺️Example:
[YouTube: “Beyond Unit Tests: 5 Shiny Node.JS Test Types (2018)” (Yoni Goldberg)](https://www.youtube.com/watch?v=-2zP494wdUY&feature=youtu.be) @@ -740,12 +705,8 @@ describe('Order service', function() { ![alt text](assets/bp-12-Yoni-Goldberg-Testing.jpeg "A test name that constitutes 3 parts") -
- - -

## ⚪ ️2.2 组件化测试可能是最有效的利器 @@ -756,10 +717,8 @@ describe('Order service', function() {
- ❌ **否则:** 你可能花了好几天写单测,却发现仅得到了 20% 的系统覆盖率。 -
代码示例 @@ -767,6 +726,7 @@ describe('Order service', function() {
### :clap: 正例: 使用 Supertest 测试 Express API (快速、覆盖很多层) + ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Jest") @@ -782,40 +742,32 @@ describe('Order service', function() {
- ❌ **否则:** 所有的变更将带来繁琐的手动测试,导致开发者惧怕发布。 -
代码示例
-### :clap: 正例: +### :clap: 正例 ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") ![alt text](assets/bp-14-testing-best-practices-contract-flow.png ) -
- -

- ## ⚪ ️ 2.4 单独测试你的中间件 :white_check_mark: **建议:** 许多人拒绝测试中间件,是因为它们仅占据系统的一小部分而且依赖真实的 Express server。这两个原因都不正确——中间件虽然小,但是影响全部或者大部分请求,而且可以被简单地作为纯函数测试(参数为 {req,res} JS 对象)。测试中间件函数,你仅需调用它,并且 spy ([比如使用 Sinon](https://www.npmjs.com/package/sinon)) {req,res} 的交互以保证函数执行了正确的行为。[node-mock-http](https://www.npmjs.com/package/node-mocks-http) 库更进一步:它还监听了 {req,res} 对象的行为。例如,它可以断言 res 对象上的 http 状态是否符合预期。(看下面的例子)
- ❌ **否则:** Express 中间件上的一个 bug === 所有或者大部分请求的 bug -
代码示例 @@ -849,9 +801,6 @@ test('A request without authentication header, should return http status 403', (
- - -

## ⚪ ️2.5 使用静态分析工具度量并指导重构 @@ -862,10 +811,8 @@ test('A request without authentication header, should return http status 403', (
- ❌ **否则:** 由于代码质量差,再新的库和 feature 也无法拯救你的 bug 和性能。 -
代码示例 @@ -881,9 +828,6 @@ test('A request without authentication header, should return http status 403', (
- - -

## ⚪ ️ 2.6 你是否准备好迎接 Node 相关的噪声 @@ -891,10 +835,8 @@ test('A request without authentication header, should return http status 403', ( :white_check_mark: **建议:** 怪异的是,大部分软件测试仅关注逻辑和数据,但是最糟糕(而且很难减轻)的往往是基础设施问题。例如,你测试过当你的进程存储过载、服务器/进程挂掉时的表现吗?或者你的监控系统会检测到 API 减慢 50% 了吗?为了测试及减轻类似问题,Netflix 设立了 [噪声工程](https://principlesofchaos.org/)。它的目的是为我们的系统在故障问题下的健壮性提供意识、框架及工具。比如,著名的工具之一 [噪声猴子](https://github.com/Netflix/chaosmonkey),随机地杀掉服务以保证我们的服务仍服务于用户,而不是仅依赖一个单独的服务器(Kubernetes 也有一个版本 [kube-monkey](https://github.com/asobti/kube-monkey) 用于杀掉 pods)。这些工具都是作用于服务器/平台层面,但如果你想测试及生产纯粹的 Node 噪声比如检查你的 Node 进程如何处理未知错误、未知的 promise rejection、v8 内存超过 1.7GB 的限制以及当事件循环经常卡住后你的 UX 是否仍正常运行?为了解决上面提到的这些问题, [node-chaos](https://github.com/i0natan/node-chaos-monkey)(alpha)提供了各种 Node 相关的噪声。
- ❌ **否则:** 墨菲定律一定会无情地砸中你的产品,跑不掉的。 -
代码示例 @@ -902,6 +844,7 @@ test('A request without authentication header, should return http status 403', (
### :clap: 正例: Node-chaos 可以生成所有类型的 Node.js 问题,因此您可以测试您的应用程序对混乱的适应能力 + ![alt text](assets/bp-17-yoni-goldberg-chaos-monkey-nodejs.png "Node-chaos can generate all sort of Node.js pranks so you can test how resilience is your app to chaos")
@@ -913,10 +856,8 @@ test('A request without authentication header, should return http status 403', ( :white_check_mark: **建议:** 参照黄金法则,每条测试需要在它自己的 DB 行中运行避免互相污染。现实中,这条规则经常被打破:为了性能提升而在执行测试前全局初始化数据库([也被称为‘test fixture’](https://en.wikipedia.org/wiki/Test_fixture))。尽管性能很重要,但是它可以通过后面讲的「分组件测试」缓和。为了减轻复杂度,我们可以在每个测试中只初始化自己需要的数据。除非性能问题真的非常显著,那么可以做一定的妥协——仅在全局放不会改变的数据(比如 query)。
- ❌ **否则:** 一部分测试挂了,我们的团队花费大量宝贵时间后发现,是由于两个测试同时改变了同一个 seed 数据导致的。 -
代码示例 @@ -946,6 +887,7 @@ it("When querying by site name, get the right site", async () => { }); ``` +
### :clap: 正例: 每个用例操作它自己的数据集 @@ -974,12 +916,10 @@ it("When updating site name, get successful confirmation", async () => { :white_check_mark: **建议:** 当专注于测试组件逻辑时,UI 细节就变成了应该剔除的噪音,这样您的测试就可以集中在纯数据上。实际上,通过抽象从代码中提取所需的数据将降低与图形实现的耦合,仅对纯数据 (vs HTML/CSS 图形细节) 断言,并禁用会拖慢速度的动画。您可能会试图避免渲染,仅测试 UI 后面的部分(例如,服务、操作、存储),但这将导致测试与实际情况不太相符,「正确的数据根本无法到达 UI」这种问题就无法发现。 -
❌ **否则:** 您的测试的纯计算数据可能在 10ms 内就准备好了,但是由于一些花哨和无关的动画,整个测试将持续500ms (100个测试 = 1分钟) -
代码示例 @@ -1014,6 +954,7 @@ test('When users-list is flagged to show only VIP, should display only VIP membe
### :thumbsdown: 反例: 混杂了 UI 细节和数据的断言 + ```javascript test('When flagging to show only VIP, should display only VIP members', () => { // Arrange @@ -1033,12 +974,8 @@ test('When flagging to show only VIP, should display only VIP members', () => {
- - -

- ## ⚪ ️ 3.2 使用不太容易改变的属性去查询 HTML 元素 :white_check_mark: **建议:**通过不太同意受图形变更印象的属性查询 HTML 元素(例如 form label,而不是 CSS selector)。如果指定的元素没有这样的属性,则创建一个专用的测试属性,如“test-id-submit-button”。这样做不仅可以确保您的功能/逻辑测试不会因为外观变化而中断,而且整个团队可以清楚地看到,测试使用了这个元素和属性,不应该删除它。 @@ -1084,6 +1021,7 @@ test('When flagging to show only VIP, should display only VIP members', () => {
### :thumbsdown: 反例: 依赖 css attribute + ```html {value} @@ -1098,12 +1036,8 @@ test('Whenever no data is passed, error metric shows zero', () => { }); ``` -
- - -
## ⚪ ️ 3.3 只要有可能,使用真实且完全渲染的组件进行测试 @@ -1116,7 +1050,6 @@ test('Whenever no data is passed, error metric shows zero', () => { ❌ **否则:** 之前通过调用组件的私有方法来测试组件的内部状态。后续重构组件时你必须重构所有测试。你真的有能力进行这种程度的维护吗? -
代码示例 @@ -1160,6 +1093,7 @@ test('Realistic approach: When clicked to show filters, filters are displayed', ``` ### :thumbsdown: 反例: 通过 shallow render 测试伪组件 + ```javascript test('Shallow/mocked approach: When clicked to show filters, filters are displayed', () => { @@ -1181,15 +1115,13 @@ test('Shallow/mocked approach: When clicked to show filters, filters are display
- -## ⚪ ️ 3.4 不要 sleep,使用框架内置的对 async 事件的支持。并且尝试提效。 +## ⚪ ️ 3.4 不要 sleep,使用框架内置的对 async 事件的支持。并且尝试提效 :white_check_mark: **建议:** 在许多情况下,被测试单元的完成时间是未知的 (例如,animation 挂起了元素表现 )——在这种情况下,不要 sleep (例如setTimeout),并是使用大多数框架提供的更靠谱的方法。一些库允许等待操作 (例如 [Cypress .request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)),另一些库提供用于等待的 API,如 [@testing-library/dom 方法 wait(expect(element))](https://testing-library.com/docs/guide-disappearance)。有时一种更优雅的方法是 stub 慢的资源,比如API,然后一旦响应时间变得确定,组件就可以显式地重新渲染。当依赖一些 sleep 的外部组件时,[加快时钟](https://jestjs.io/docs/en/timer-mocks)可能会提供帮助。sleep 是一种需要避免的模式,因为它会迫使您的测试变得缓慢或有风险(当等待的时间太短时)。当 sleep 和轮询不可避免且测试框架原生不支持时,一些npm库 (如 [wait-for-expect](https://www.npmjs.com/package/wait-for-expect)) 可以帮助解决半确定性问题。
❌ **否则:** 当 sleep 时间长时,测试速度会慢一个数量级。当尝试缩短 sleep 时间时,如果被测试的单元没有及时响应,则测试将失败。这时你不得不在脆弱的测试和糟糕的性能之间进行权衡。 -
代码示例 @@ -1229,6 +1161,7 @@ test('movie title appears', async () => { ``` ### :thumbsdown: 反例: 自己写 sleep 代码 + ```javascript test('movie title appears', async () => { @@ -1252,7 +1185,6 @@ test('movie title appears', async () => {
-
## ⚪ ️ 3.5 观察内容是如何通过网络提供的 @@ -1274,10 +1206,8 @@ test('movie title appears', async () => { ![](/assets/lighthouse2.png "Lighthouse page load inspection report") -
-
## ⚪ ️ 3.6 stub 古怪或缓慢的资源如后端 API @@ -1288,7 +1218,6 @@ test('movie title appears', async () => { ❌ **否则:** 测试的平均时长不在是几毫秒,一个经典的 API 调用花费 100ms+,这使得每个用例变慢 ~20x。 -
代码示例 @@ -1296,6 +1225,7 @@ test('movie title appears', async () => {
### :clap: 正例: stub 或拦截 API 调用 + ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with react-testing-library") @@ -1395,9 +1325,6 @@ beforeEach(setUser => () {
- - -
## ⚪ ️ 3.9 创建一个 E2E 冒烟测试,仅仅走一遍网站地图 @@ -1408,7 +1335,6 @@ beforeEach(setUser => () { ❌ **否则:** 一切似乎都很完美,所有的测试都通过了,生产环境健康检查也是 OK 的,但是支付组件有一些打包问题,只有 `/Payment` 路径没有渲染。 -
代码示例 @@ -1416,8 +1342,10 @@ beforeEach(setUser => () {
### :clap: 正例: 一个跑一遍所有页面的冒烟测试 + ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + ```javascript it('When doing smoke testing over all page, should load them all successfully', () => { // exemplified using Cypress but can be implemented easily @@ -1433,7 +1361,6 @@ it('When doing smoke testing over all page, should load them all successfully',
-
## ⚪ ️ 3.10 将测试以实时协作文档的形式公开 @@ -1442,7 +1369,6 @@ it('When doing smoke testing over all page, should load them all successfully', ❌ **否则:** 你在测试上耗费了大量的资源,如果不利用这项投资来获取更大的价值,是很可惜的。 -
代码示例 @@ -1452,6 +1378,7 @@ it('When doing smoke testing over all page, should load them all successfully', ### :clap: 正例: 使用 cucumber-js 以人类语言描述测试 ![](https://img.shields.io/badge/🔨%20Example%20using%20Cocumber-blue.svg "Examples using Cucumber") + ```javascript // this is how one can describe tests using cucumber: plain language that allows anyone to understand and collaborate @@ -1470,24 +1397,19 @@ Feature: Twitter new tweet ``` ### :clap: 正例: 使用 Storybook 展示我们的组件及其各种状态和输入 -![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") +![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook")
- - - ## ⚪ ️ 3.11 使用自动化工具检测可视化问题 - :white_check_mark: **建议:** 设置自动化工具来抓取 UI 截屏,并在变更后检测内容重叠或中断等可视化问题。这样不仅可以确保数据的正确性,而且用户可以方便地看到它。这种技术没有被广泛采用,我们的测试思维更倾向于功能测试,但它代表了真实的用户体验,而且可以轻易地发现跨多设备类型的 UI bug。目前部分免费工具可以提供一些基础功能——生成和保存屏幕截图以供肉眼检查。虽然这种方法对于小应用来说可能已经足够了,但是它的缺陷与任何其他手动测试一样
:任何变更后都需要耗费人力来处理。另一方面,由于缺乏清晰的定义,自动检测 UI 问题非常具有挑战性——这就是“视觉回归”领域解决这个难题的切入点:对比旧 UI 与最新的更改并检测差异。一些开源/免费的工具可以提供这个能力 (例如: [wraith](https://github.com/BBC-News/wraith)、PhantomCSS) 但可能安装耗时比较久。一些商业工具 (如  [Applitools](https://applitools.com/)、[Percy.io](https://percy.io/)) 则更进一步,它们简化了安装过程,并封装了高级特性,如管理 UI、告警、通过去除“视觉噪音”(如广告、动画) 进行智能捕获,甚至可以分析引发问题的 DOM/css 变化的根本原因。
❌ **否则:** 如何评判这样的页面好不好:内容显示正确 (100%测试通过)、加载迅速但有一半内容区域隐藏? -
代码示例 @@ -1500,7 +1422,6 @@ Feature: Twitter new tweet
- ### :clap: 正例: 配置 wraith 来捕获并比对 UI 快照 ![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg @@ -1557,16 +1478,10 @@ describe('visual validation', () => { }); ``` - - -
- -

- # 第四章: 度量测试效果

@@ -1579,10 +1494,8 @@ describe('visual validation', () => {
- ❌ **否则:** 信心和数字是相辅相成的,如果无法确保你的测试已经覆盖了了大部分的系统,那你将会害怕,害怕会让你慢下来。 -
代码示例 @@ -1590,6 +1503,7 @@ describe('visual validation', () => {
### :clap: 正例: 一个经典的覆盖率报告 + ![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report")
@@ -1603,8 +1517,6 @@ describe('visual validation', () => {
- -

## ⚪ ️ 4.2 检查覆盖率报告,以发现未覆盖的区域和其他奇怪的地方 @@ -1613,10 +1525,8 @@ describe('visual validation', () => {
- ❌ **否则:** 如果你不知道你的代码中有哪些部分没有被测试到,则你没法准确定位问题的来源。 -
代码示例 @@ -1629,7 +1539,6 @@ describe('visual validation', () => {
-

## ⚪ ️ 4.3 使用「变异测试」度量逻辑覆盖率 @@ -1643,7 +1552,6 @@ describe('visual validation', () => { 相对于传统覆盖率,得知所有或者大部分变异被杀掉会给予你更高的信心,而两者花费的时间差不多。
- ❌ **否则:** 你会误以为 85% 的覆盖率代表你的测试会发现你代码中的 85% 的 bug.
@@ -1656,6 +1564,7 @@ describe('visual validation', () => { ![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Cypress to illustrate the idea") + ```javascript function addNewOrder(newOrder) { logger.log(`Adding new order ${newOrder}`); @@ -1670,6 +1579,7 @@ it("Test addNewOrder, don't use such test names", () => { });//Triggers 100% code coverage, but it doesn't check anything ``` +
### :clap: 正例: Stryker 报告,一个编译测试工具,发现并统计没有被测试到的代码(变异) @@ -1678,8 +1588,6 @@ it("Test addNewOrder, don't use such test names", () => {
- -

## ⚪ ️4.4 使用 Test linter 防止测试代码问题 @@ -1688,10 +1596,8 @@ it("Test addNewOrder, don't use such test names", () => {
- ❌ **否则:** 当你满足于 90% 的代码覆盖率和 100% 的绿色用例时,发现很多测试啥都没断言,很多测试直接被 skip 掉了。但愿你没有基于这个错误认知做过额外的构建。 -
代码示例 @@ -1717,7 +1623,6 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test

- # 第五章:持续集成(CI)以及其他质量度量手段

@@ -1737,13 +1642,11 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test
### :thumbsdown: 反例: 出错的对象被错误地抛出,没有显示这个错误的堆栈信息。好在 ESLint 捕获到了后面的生产错误 + ![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug")
- - -

# ⚪ ️ 5.2 通过本地的开发 CI 来缩短反馈循环 @@ -1753,17 +1656,15 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test 目前已有一些 CI 供应商 (如: [CircleCI load CLI](https://circleci.com/docs/2.0/local-cli/)) 支持在本地执行 CI。一些商业工具如 [wallaby](https://wallabyjs.com/) 为开发原型提供了非常有用的测试能力。或者你可以仅仅在 package.json 中添加 npm 脚本来跑一些质量命令——使用工具如 [concurrently](https://www.npmjs.com/package/concurrently) 来并行执行,并在任何工具失败后抛出非 0 exit code。则开发者只需执行一个命令(如 `npm run quality` )来快速获取反馈。可以用 githook 来取消没有通过质量检查的提交([husky](https://github.com/typicode/husky) 可以帮到你)。
- ❌ **否则:** 当质量检查结果在提交后第二天才收到反馈,则测试不再是开发的一部分了。 -
代码示例
-### :clap: 正例: 用于执行代码质量检查的 npm 脚本,在主动触发或用户尝试提交新代码时并行执行。 +### :clap: 正例: 用于执行代码质量检查的 npm 脚本,在主动触发或用户尝试提交新代码时并行执行 ```javascript "scripts": { @@ -1786,9 +1687,6 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test
- - -

# ⚪ ️5.3 在真实的生产环境镜像中执行端到端测试 @@ -1799,17 +1697,15 @@ Kubernetes 强大的生态系统还没有形成一个易用的标准工具用于
- ❌ **否则:** 生产和测试环境使用不同的技术,需要维护两个部署模型,并将开发人员和 ops 团队分隔开来。 -
代码示例
-### :clap: 正例: 动态生成 Kubernetes 集群的 CI 管道 (贡献: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) +### :clap: 正例: 动态生成 Kubernetes 集群的 CI 管道 (贡献: Dynamic-environments Kubernetes]()) ```yaml deploy: @@ -1830,19 +1726,14 @@ name: test-for-ci
- - - -

## ⚪ ️5.4 并行测试工作 -:white_check_mark: **建议:** 只要操作合理,测试是你 7x24 小时的朋友,为你提供非常及时的反馈。实际上,在单个线程上执行 500 个单元测试可能需要很长时间。幸运的是,现代测试运行器和 CI 平台(如 [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) 和 [Mocha extensions](https://github.com/yandex/mocha-parallel-tests))可以将测试并行化为多个进程,以显著缩短反馈时间。 一些CI供应商也支持跨容器并行化测试,这进一步缩短了反馈循环。 无论是在本地多个进程,还是在使用多台机器的某些云 CLI 上 - 并行化需要保证测试用例的独立性,因为每个用例可能在不同的进程上运行。 +:white_check_mark: **建议:** 只要操作合理,测试是你 7x24 小时的朋友,为你提供非常及时的反馈。实际上,在单个线程上执行 500 个单元测试可能需要很长时间。幸运的是,现代测试运行器和 CI 平台(如 [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) 和 [Mocha extensions](https://github.com/yandex/mocha-parallel-tests))可以将测试并行化为多个进程,以显著缩短反馈时间。 一些CI供应商也支持跨容器并行化测试,这进一步缩短了反馈循环。 无论是在本地多个进程,还是在使用多台机器的某些云 CLI 上 - 并行化需要保证测试用例的独立性,因为每个用例可能在不同的进程上运行。 ❌ **否则:** 在推送新代码 1 小时后获得测试结果,而你已经在写下一个 feature 了。 -
代码示例 @@ -1850,28 +1741,27 @@ name: test-for-ci
### :clap: 正例: Mocha parallel & Jest 轻松地加速了传统的 Mocha,感谢并行测试([贡献:JavaScript测试运行基准](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) + ![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)")
- - -

## ⚪ ️5.5 使用许可证和抄袭检查避免法务问题 + :white_check_mark: **建议:** 许可和抄袭问题可能不是您现在主要关注的问题,但为什么不在10分钟内加上这个能力呢? 许多 npm 包,如 [license check](https://www.npmjs.com/package/license-checker) 和 [plagiarism check](https://www.npmjs.com/package/plagiarism-checker)(商业的,但是有免费选项)可以很容易地加入您的 CI 管道,并检查一些坑:依赖限制性许可证或从Stackoverflow复制粘贴的代码,或者很明显地侵犯了某些版权。 ❌ **否则:** 无意中,开发人员可能会使用包含不适当许可证的软件包或复制粘贴商业代码并遇到法务问题。 -
代码示例
-### :clap: 正例: +### :clap: 正例 + ```javascript //install license-checker in your CI environment or also locally npm install -g license-checker @@ -1885,19 +1775,16 @@ license-checker --summary --failOn BSD ![alt text](assets/bp-25-nodejs-licsense.png) -
- -

## ⚪ ️5.6 持续检查有漏洞的依赖 + :white_check_mark: **建议:** 即使是最知名的依赖(如 Express)也存在已知的漏洞。 这可以通过使用社区工具(如 [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit))或商业工具(如 [snyk](https://snyk.io/))(也提供免费的社区版本)轻松解决。 可以在每次构建时都可以从 CI 调用他俩。 ❌ **否则:** 在没有专用工具的帮助下保持代码远离漏洞,将需要不断关注有关新威胁的发布信息。 这相当乏味。 -
代码示例 @@ -1905,13 +1792,11 @@ license-checker --summary --failOn BSD
### :clap: 正例: NPM Audit 结果 + ![alt text](assets/bp-26-npm-audit-snyk.png "NPM Audit result")
- - -

## ⚪ ️5.7 自动升级依赖 @@ -1926,10 +1811,8 @@ license-checker --summary --failOn BSD
- ❌ **否则:** 您的生产环境运行的包已被其作者明确标记为有风险。 -
代码示例 @@ -1940,10 +1823,8 @@ license-checker --summary --failOn BSD ![alt text](assets/bp-27-yoni-goldberg-npm.png "Nncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") -
-

## ⚪ ️ 5.8 其他的,与 Node 无关的,CI 小建议 @@ -1962,7 +1843,6 @@ license-checker --summary --failOn BSD
- ❌ **否则:** 你会错过多年来智慧的结晶

@@ -1972,10 +1852,8 @@ license-checker --summary --failOn BSD :white_check_mark: **建议:** 质量检查是用于发现意外,你覆盖的部分越多,你就越可能尽早地发现问题。 在开发包或运行具有各种配置和 Node 版本的多客户生产环境时,CI 必须在所有配置的组合上运行测试管道。 例如,假设我们的某些客户使用 MySQL,另一批客户使用 Postgres。一些 CI 工具支持一种称为“Matrix”的功能,该功能可以针对 MySQL、Postgres 和多个 Node 版本(如8、9、10)的所有组合执行测试。 只要配置即可完成而无需任何额外工作。 其他不支持 Matrix 的 CI 可能可以通过扩展或一定调整来实现这个功能。
- ❌ **否则:** 在辛辛苦苦写完所有用例编写之后,怎么可以因为配置问题而让漏洞溜进来? -
代码示例 @@ -2003,8 +1881,6 @@ script: # Team - - ## Yoni Goldberg
@@ -2017,21 +1893,20 @@ script:
-**Workshop:** 👨‍🏫 是否想在您自己的办公室中(欧洲和美国)学习所有这些实践和技术? [在此处注册我的测试工作室](https://testjavascript.com/) +**Workshop:** 👨‍🏫 是否想在您自己的办公室中(欧洲和美国)学习所有这些实践和技术? [在此处注册我的测试工作室](
**关注:** -* [🐦 Twitter](https://twitter.com/goldbergyoni/) -* [📞 Contact](https://testjavascript.com/contact-2/) -* [✉️ Newsletter](https://testjavascript.com/newsletter//) +- [🐦 Twitter](https://twitter.com/goldbergyoni/) +- [📞 Contact](https://testjavascript.com/contact-2/) +- [✉️ Newsletter](https://testjavascript.com/newsletter//)


- -## [Bruno Scheufler](https://github.com/BrunoScheufler) +## [Bruno Scheufler](https://github.com/BrunoScheufler) **角色:** 技术评审人和顾问 diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 2b20f0f0..ac455c50 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -18,7 +18,6 @@ 首先了解任何應用程式都通用的測試實踐。然後再深入研究你選擇的領域:前端/UI、後端、CI 或者全部。 -
### 作者 Yoni Goldberg @@ -375,7 +374,7 @@ it("When a valid product is about to be deleted, ensure an email is sent", async :white_check_mark: **建議:** 生產環境中的 bug 通常是在一些特殊或者意外的輸入下出現的 — 所以測試的輸入資料越真實,越容易在早期抓住問題。使用現有的一些函式庫(比如 [Faker](https://www.npmjs.com/package/faker))去造"假"真實數據來模擬生產環境數據的多樣性和形式。比如,這些函示庫可以產生真實的電話號碼、用戶名稱、信用卡、公司名稱等等。你還可以創建一些測試(在單元測試之上,而不是替代)生產隨機 fakers 數據來擴充你的測試單元,甚至從生產環境中導入真實的資料。如果想要更進階的話,請看下一個項目:基於屬性的測試 (property-based testing)。
-❌ **否則:** 你要部屬的程式都在 "foo" 之類的輸入值中正確的通過測試,結果上線之後收到像是 ```@3e2ddsf . ##’ 1 fdsfds . fds432 AAAA``` 之類的輸入值後掛掉了。 +❌ **否則:** 你要部屬的程式都在 "foo" 之類的輸入值中正確的通過測試,結果上線之後收到像是 ```@3e2ddsf . ##’ 1 fdsfds . fds432 AAAA``` 之類的輸入值後掛掉了。
@@ -474,7 +473,7 @@ describe("Product service", () => { 另一方面,"classic snapshots"的教學和工具鼓勵將大文件 (如組件的渲染結果、API 的 JSON 結果) 存儲在一些外部媒介上,並確保每次測試運行時,將收到的結果與保存的版本進行比較。舉個例子,這將會隱性地將我們的測試與包含3000個數值的1000行內容耦合在一起,而測試者從未閱讀和推理過這些數據。為什麼這樣是不對的? 這樣做,將會有1000個原因讓你的測試失敗 - 只要有一行改變,快照比對就會 fail,而這可能會經常發生。多頻繁?當有每一個空格、註解或一點 CSS/HTML 的變化。不僅如此,測試名稱也不會提供關於失敗的線索,因為它只是檢查這1000行是否有變化,而且它還鼓勵測試者去接受一個他無法檢查和驗證的大文件作為期望的結果。所有這些都是測試目標不明確、測試目標過多的症狀。 -值得注意的是,在少數情況下,大型的外部快照是可以接受的 - 當斷言的對象是 schema 而不是所有內容時 (提取出要的值並專注在某個欄位上),或者當收到的文件內容幾乎不會改變時。 +值得注意的是,在少數情況下,大型的外部快照是可以接受的 - 當斷言的對象是 schema 而不是所有內容時 (提取出要的值並專注在某個欄位上),或者當收到的文件內容幾乎不會改變時。
@@ -750,13 +749,13 @@ test("Then there should not be a new transfer record", () => {}); ## ⚪ ️2.1 豐富您的測試組合:不局限於單元測試和測試金字塔 -:white_check_mark: **建議:** 雖然 [測試金字塔](https://martinfowler.com/bliki/TestPyramid.html) 已經有超過十年的歷史了,但他仍然是個很好的模型,他提出了三種測試類型,並影響了大多數開發者的測試策略。與此同時,大量閃亮的新測試技術出現了,並隱藏在測試金字塔的陰影下。考慮到近十年來我們所看到的所有巨變 (Microservices, cloud, serverless),這個非常老的模型是否仍能適用於所有類型的應用?測試界不應該考慮新的測試技術嗎? +:white_check_mark: **建議:** 雖然 [測試金字塔](https://martinfowler.com/bliki/TestPyramid.html) 已經有超過十年的歷史了,但他仍然是個很好的模型,他提出了三種測試類型,並影響了大多數開發者的測試策略。與此同時,大量閃亮的新測試技術出現了,並隱藏在測試金字塔的陰影下。考慮到近十年來我們所看到的所有巨變 (Microservices, cloud, serverless),這個非常老的模型是否仍能適用於所有類型的應用?測試界不應該考慮新的測試技術嗎? 不要誤會,在 2019 年,測試金字塔、TDD、單元測試仍然是強大的技術,且對於大多數應用仍是最佳選擇。但是像其他模型一樣,儘管它有用,但是一定[會在某些時候出問題](https://en.wikipedia.org/wiki/All_models_are_wrong)。例如,我們有一個 IoT 的應用程式,將許多事件傳入一個 Kafka/RabbitMQ 這樣的 message-bus 中,然後這些事件流入資料庫並被經由 UI 來做查詢。我們真的需要花費 50% 的測試預算去為這個幾乎沒有邏輯的中心化的整合應用程式寫單元測試嗎?隨著應用類型 (bots, crypto, Alexa-skills) 的多樣增長,測試金字塔可能將不再是某些場景的最佳選擇了。 是時候豐富你的測試組合並了解更多的測試類型了(下一節會給你一些小建議),這些類似於測試金字塔的思維模型與你所面臨的現實問題會更加匹配("嘿,我們的 API 掛了,我們來寫 consumer-driven contract testing 吧!")。讓您的測試多樣化,比如建立基於風險分析的檢查模型 — 評估可能出現問題的地方,並提供一些預防措施以減輕這些潛在風險。 -需要注意的是:軟體世界中的 TDD 模型面臨兩個極端的態度,一些人鼓吹到處使用它,另一些人則認為它是魔鬼。每個說絕對的人都是錯的 :] +需要注意的是:軟體世界中的 TDD 模型面臨兩個極端的態度,一些人鼓吹到處使用它,另一些人則認為它是魔鬼。每個說絕對的人都是錯的 :]
@@ -823,7 +822,7 @@ test("Then there should not be a new transfer record", () => {});
-### :clap: 正例: +### :clap: 正例 ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") @@ -901,7 +900,7 @@ Credit: { ## ⚪ ️ 3.2 使用不易改變的屬性來查询 HTML 元素 -:white_check_mark: **建議:** 使用不太容易受畫面變更而影響的屬性來查詢 HTML 元素 (例如 form label,而不是 CSS selector)。如果指定的元素沒有這樣的屬性,則創建一個專用的測試屬性,如 `test-id-submit-button`。這樣做不僅可以確保您的功能/邏輯測試不會因為外觀變化而中斷,而且整個團隊可以清楚地看到,測試案例使用了這個元素和屬性,不應該刪除它。 +:white_check_mark: **建議:** 使用不太容易受畫面變更而影響的屬性來查詢 HTML 元素 (例如 form label,而不是 CSS selector)。如果指定的元素沒有這樣的屬性,則創建一個專用的測試屬性,如 `test-id-submit-button`。這樣做不僅可以確保您的功能/邏輯測試不會因為外觀變化而中斷,而且整個團隊可以清楚地看到,測試案例使用了這個元素和屬性,不應該刪除它。
@@ -1262,7 +1261,7 @@ test("When no products exist, show the appropriate message", () => {
-❌ **否則:** UI 可能在功能測試上花費了大量的精力,但最後才發現後端回傳的內容 (UI 要使用的資料格式) 與預期中的不一樣。 +❌ **否則:** UI 可能在功能測試上花費了大量的精力,但最後才發現後端回傳的內容 (UI 要使用的資料格式) 與預期中的不一樣。
@@ -1272,7 +1271,7 @@ white_check_mark: **建議:** 在涉及真實的後端並必須使用有效的
-❌ **否則:** 給定 200 個測試案例,假設登錄需要花費的時間為 100ms,則至少需要花費 20s,在這一遍遍的登錄上。 +❌ **否則:** 給定 200 個測試案例,假設登錄需要花費的時間為 100ms,則至少需要花費 20s,在這一遍遍的登錄上。
@@ -1520,7 +1519,7 @@ describe("visual validation", () => { ### :thumbsdown: 反例:這個測試覆蓋率的報告出了什麼問題? -基於一個真實世界的情境,我們在 QA 中追蹤了我們應用程式的使用情況,並發現了這個有趣的登錄模式 (提示:登入失敗的數量不成正比的,顯然是有問題的。最後發現,有一些前端的 bug 一直在打後端的登入 API) +基於一個真實世界的情境,我們在 QA 中追蹤了我們應用程式的使用情況,並發現了這個有趣的登錄模式 (提示:登入失敗的數量不成正比的,顯然是有問題的。最後發現,有一些前端的 bug 一直在打後端的登入 API) ![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report?") @@ -1628,7 +1627,7 @@ it("Test name", () => { // *error:no-identical-title. Assign unique titles to te
-### :thumbsdown: 反例:Error 物件被拋出,這樣的錯誤不會出現 stack trace。幸運的是,ESLint 抓到了這個 bug。 +### :thumbsdown: 反例:Error 物件被拋出,這樣的錯誤不會出現 stack trace。幸運的是,ESLint 抓到了這個 bug ![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") @@ -1651,7 +1650,7 @@ it("Test name", () => { // *error:no-identical-title. Assign unique titles to te
-### :clap: 正例:用來執行程式品質檢查的 npm script,在開發者主動觸發或嘗試提交新程式時執行。 +### :clap: 正例:用來執行程式品質檢查的 npm script,在開發者主動觸發或嘗試提交新程式時執行 ```javascript "scripts": { @@ -1746,7 +1745,7 @@ name: test-for-ci
-### :clap: 正例: +### :clap: 正例 ```javascript //install license-checker in your CI environment or also locally @@ -1805,7 +1804,7 @@ license-checker --summary --failOn BSD
-### :clap: 正例:[ncu](https://www.npmjs.com/package/npm-check-updates) 可以手動或在 CI pipeline 中使用,以檢測程式落後最新版本多少。 +### :clap: 正例:[ncu](https://www.npmjs.com/package/npm-check-updates) 可以手動或在 CI pipeline 中使用,以檢測程式落後最新版本多少 ![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") @@ -1901,4 +1900,4 @@ Took care to revise, improve, lint and polish all the texts **Role:** Helps keep this project running, and reviews security related practices -**About:** Loves working on Node.js projects and web application security. \ No newline at end of file +**About:** Loves working on Node.js projects and web application security. diff --git a/readme.kr.md b/readme.kr.md index a4dd1383..6d0b3f90 100644 --- a/readme.kr.md +++ b/readme.kr.md @@ -7,13 +7,16 @@
## 📗 철저하고 매우 포괄적인 45가지 이상의 모범 사례 + JavaScript 및 Node.js에 대한 A부터 Z까지의 믿음직한 가이드입니다. 수십 가지 최고의 블로그 게시물, 서적 및 도구를 요약하고 정리합니다. ## 🚢 기초를 뛰어넘어 고급으로 + 운영중인 제품의 테스트, 돌연변이 테스트, 속성 기반 테스트 및 기타 여러 전략적 & 전문 도구와 같은 고급 주제로 넘어가는 여정을 경험하십시오. 이 가이드의 모든 단어를 읽으면 당신의 테스트 기술이 평균보다 높아질 수 있습니다. ## 🌐 Full-stack: 프론트, 백엔드, CI, 무엇이든 + 모든 응용프로그램 계층의 기초가 되는 유비쿼터스 테스트 방법을 이해하는 것으로부터 시작하십시오. 그런 다음 프론트엔드/UI, 백엔드, CI 혹은 이 모든것을 공부하세요.
@@ -50,7 +53,6 @@ JavaScript 및 Node.js에 대한 A부터 Z까지의 믿음직한 가이드입니 감시자를 감시하기 - 테스트 품질 측정(4개) - #### [`섹션 5: 지속적인 통합`](#섹션-5️⃣-지속적인-통합) 자바스크립트 세계에서 CI에 대한 지침(9개) @@ -72,7 +74,7 @@ JavaScript 및 Node.js에 대한 A부터 Z까지의 믿음직한 가이드입니 선택적인 체리픽 기술, 툴 그리고 비용-효율적이고 뛰어난 ROI를 제공하는 테스트 대상 선정으로 이러한 목적을 달성할 수 있습니다. 필요한 만큼의 테스트, 융통성 있게 유지하려는 노력, 때로는 애자일함과 단순성을 위해 일부 테스트와 신뢰성을 포기하는 것도 가치가 있습니다. ![alt text](/assets/headspace.png "우리 머리속은 부가적인 복잡한 것들을 생각할 여유가 없습니다.") - + 아래 대부분의 조언은 이 원칙의 파생입니다. ### 시작할 준비 되셨나요? @@ -83,7 +85,7 @@ JavaScript 및 Node.js에 대한 A부터 Z까지의 믿음직한 가이드입니
-## ⚪ ️ 1.1 각 테스트 이름은 세 부분으로 구성된다. +## ⚪ ️ 1.1 각 테스트 이름은 세 부분으로 구성된다 :white_check_mark: **이렇게 해라:** 테스트는 현재 애플리케이션의 개정판이 요구 사항을 충족하는지 여부를 다음과 같은 사람들에게 알려야합니다: 배포를 할 테스터, DevOps 엔지니어, 2년 후의 미래에 코드가 익숙하지 않은 사람. 테스트가 요구 사항 수준에서 작성되어 있고 세 부분으로 구성되어 있다면, 목적을 이룰 수 있습니다: @@ -178,7 +180,7 @@ describe('고객 분류기', () => {
-### :thumbsdown: 올바르지 않은 예: 분리 되어있지 않고 한 벌로 작성되어 있어 해석하기 어렵다. +### :thumbsdown: 올바르지 않은 예: 분리 되어있지 않고 한 벌로 작성되어 있어 해석하기 어렵다 ```javascript test('프리미엄으로 분류해야 합니다.', () => { @@ -195,6 +197,7 @@ test('프리미엄으로 분류해야 합니다.', () => {

## ⚪ ️ 1.3 제품의 언어로 예상값을 설명: BDD 스타일의 Assertion을 사용 + :white_check_mark: **이렇게 해라:** 테스트를 선언적 스타일로 작성하면 읽는 사람이 즉시 파악할 수 있습니다. 조건부 논리로 채워진 명령형 코드로 작성하면 테스트를 읽기가 쉽지 않습니다. 그런 의미에서 임의의 사용자 정의 코드를 사용하지 말고, 선언적 BDD 스타일의 expect 또는 should를 사용하여 인간과 같은 언어로 테스트를 작성하십시오. Chai & Jest에 원하는 Assertion이 포함되어 있지 않고 반복성이 높은 경우 [extending Jest matcher (Jest)](https://jestjs.io/docs/en/expect#expectextendmatchers) 혹은 [custom Chai plugin](https://www.chaijs.com/guide/plugins/) 작성을 고려하십시오.
@@ -209,7 +212,7 @@ test('프리미엄으로 분류해야 합니다.', () => { "Examples with Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") -### :thumbsdown: 올바르지 않은 예: 읽는 사람은 테스트 스토리를 이해하기 위해 짧지않은 명령형 코드를 훑어봐야 합니다. +### :thumbsdown: 올바르지 않은 예: 읽는 사람은 테스트 스토리를 이해하기 위해 짧지않은 명령형 코드를 훑어봐야 합니다 ```javascript test("관리자 요청이 들어오면 정렬된 관리자 목록만 결과에 포함된다." , () => { @@ -235,7 +238,7 @@ test("관리자 요청이 들어오면 정렬된 관리자 목록만 결과에
-### :clap: 올바른 예: 다음과 같은 선언적 테스트는 이해하기 쉽습니다. +### :clap: 올바른 예: 다음과 같은 선언적 테스트는 이해하기 쉽습니다 ```javascript it("관리자 요청이 들어오면 정렬된 관리자 목록만 결과에 포함된다." , () => { @@ -264,7 +267,7 @@ it("관리자 요청이 들어오면 정렬된 관리자 목록만 결과에 포
-### :thumbsdown: 올바르지 않은 예: 테스트 케이스는 이유없이 내부를 테스트합니다. +### :thumbsdown: 올바르지 않은 예: 테스트 케이스는 이유없이 내부를 테스트합니다 ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") @@ -295,7 +298,7 @@ it("화이트박스 테스트: 내부 method가 VAT 0을 받으면 0을 반환

-## ⚪ ️ 1.5 올바른 테스트 더블 선택: Stub과 Spy를 위한 Mock을 피하십시오. +## ⚪ ️ 1.5 올바른 테스트 더블 선택: Stub과 Spy를 위한 Mock을 피하십시오 :white_check_mark: **이렇게 해라:** 테스트 더블은 어플리케이션 내부에 연결되어 있기때문에 필요악이지만 일부는 엄청난 가치를 제공합니다(
[테스트 더블에 대한 알림: mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). @@ -317,7 +320,7 @@ it("화이트박스 테스트: 내부 method가 VAT 0을 받으면 0을 반환 ![](https://img.shields.io/badge/🔧%20Example%20using%20Sinon-blue.svg "Examples with Mocha & Chai") - + ```javascript it("유효한 제품을 삭제하려고 할 때, 올바른 제품과 올바른 구성 정보로 데이터 액세스 DAL을 한 번 호출했는지 확인한다", async () => { // 이미 제품을 추가했다고 가정 @@ -331,7 +334,7 @@ it("유효한 제품을 삭제하려고 할 때, 올바른 제품과 올바른
-### :clap:올바른 예: spy는 요구사항을 테스트하는데 초점을 두고있지만, 내부를 건드리는 side-effect를 피할 순 없습니다. +### :clap:올바른 예: spy는 요구사항을 테스트하는데 초점을 두고있지만, 내부를 건드리는 side-effect를 피할 순 없습니다 ```javascript it("유효한 제품을 삭제하려고 할 때, 메일을 보낸다", async () => { @@ -364,8 +367,7 @@ it("유효한 제품을 삭제하려고 할 때, 메일을 보낸다", async () ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") - - + ```javascript const addProduct = (name, price) =>{ const productNameRegexNoSpace = /^\S*$/;// 공백은 허용되지 않음 @@ -403,11 +405,11 @@ it("더 나은 것: 유효한 제품이 추가된다면, 성공을 얻는다.",

-## ⚪ ️ 1.7  프로퍼티 기반(Property-based) 테스트를 통해 다양한 인풋 값 조합으로 테스트를 하십시오. +## ⚪ ️ 1.7  프로퍼티 기반(Property-based) 테스트를 통해 다양한 인풋 값 조합으로 테스트를 하십시오 :white_check_mark: **이렇게 해라:** 우리는 일반적으로 적은 수의 인풋 샘플 데이터를 가지고 테스트를 합니다. 심지어 인풋 데이터 형식이 실제 데이터와 비슷할 때에도 다음과 같이 제한된 인풋 조합으로만 테스트를 커버합니다.(method(‘’, true, 1), method(“string” , false” , 0)) 하지만, 운영시에는 5개의 파라미터를 가지는 API는 수 천 개의 다른 조합의 파라미터로 호출 될 수 있고, 이 중 하나가 우리의 시스템을 다운시킬 수도 있습니다. 그렇다면 만약 1000 가지 조합의 인풋값을 자동으로 생성하고 올바른 응답을 반환하지 못하는 인풋값을 찾아내는 단위 테스트를 작성할 수 있다면 어떨까요? -프로퍼티 기반 테스트는 단위 테스트에 모든 가능한 인풋 조합을 사용하여 생각하지 못 한 버그를 찾을 확률을 높여줍니다. 예를들어, 다음의 메소드가 주어졌을 때 — addNewProduct(id, name, isDiscount) — 프로퍼티 기반 테스트 라이브러리들은 다양한 파라미터 (number, string, boolean) 조합으로 - (1, “iPhone”, false), (2, “Galaxy”, true) - 이 메소드를 호출합니다. [js-verify](https://github.com/jsverify/jsverify) 나 [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation) 같은 라이브러리를 지원하는 테스트 러너들 (Mocha, Jest, etc) 중 당신이 가장 선호하는 방법을 통해 프로퍼티 기반 테스트를 할 수 있습니다. -업데이트 : Nicolas Dubien가 코멘트를 통해 더 많은 부가적인 기능들을 제공하고 활발하게 유지보수되고 있는 라이브러리 [fast-check](https://github.com/dubzzz/fast-check#readme)를 추천해 주었습니다. +프로퍼티 기반 테스트는 단위 테스트에 모든 가능한 인풋 조합을 사용하여 생각하지 못 한 버그를 찾을 확률을 높여줍니다. 예를들어, 다음의 메소드가 주어졌을 때 — addNewProduct(id, name, isDiscount) — 프로퍼티 기반 테스트 라이브러리들은 다양한 파라미터 (number, string, boolean) 조합으로 - (1, “iPhone”, false), (2, “Galaxy”, true) - 이 메소드를 호출합니다. [js-verify](https://github.com/jsverify/jsverify) 나 [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation) 같은 라이브러리를 지원하는 테스트 러너들 (Mocha, Jest, etc) 중 당신이 가장 선호하는 방법을 통해 프로퍼티 기반 테스트를 할 수 있습니다. +업데이트 : Nicolas Dubien가 코멘트를 통해 더 많은 부가적인 기능들을 제공하고 활발하게 유지보수되고 있는 라이브러리 [fast-check](https://github.com/dubzzz/fast-check#readme)를 추천해 주었습니다.
@@ -419,7 +421,7 @@ it("더 나은 것: 유효한 제품이 추가된다면, 성공을 얻는다.",
-### :clap: 올바른 예: “fast-check”를 사용하여 다양한 인풋 조합으로 테스트 하십시오. +### :clap: 올바른 예: “fast-check”를 사용하여 다양한 인풋 조합으로 테스트 하십시오 ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") @@ -444,7 +446,7 @@ describe("Product service", () => {

-## ⚪ ️ 1.8 필요한 경우 짧거나 인라인 스냅샷만 사용하십시오. +## ⚪ ️ 1.8 필요한 경우 짧거나 인라인 스냅샷만 사용하십시오 :white_check_mark: **이렇게 해라:** [스냅샷 테스트](https://jestjs.io/docs/en/snapshot-testing)가 필요한 경우 외부 파일이 아닌 테스트의 일부 ([인라인 스냅샷](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots))에 포함 된 짧고 집중된 스냅샷(3~7 라인)만 사용하십시오. 이 지침을 따르면 따로 설명이 필요없고 잘 깨지지 않는 테스트가 됩니다. @@ -466,7 +468,7 @@ describe("Product service", () => { ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") - + ```javascript it('TestJavaScript.com 이 올바르게 랜더링 된다.', () => { @@ -487,7 +489,7 @@ expect(receivedPage).toMatchSnapshot();
-### :clap: 올바른 예: expectation이 잘 보이고 집중된다. +### :clap: 올바른 예: expectation이 잘 보이고 집중된다 ```javascript it('TestJavaScript.com 홈페이지를 방문하면 메뉴가 보인다.', () => { @@ -515,7 +517,7 @@ expect(menu).toMatchInlineSnapshot(`

-## ⚪ ️ 1.9 테스트 데이터를 글로벌로 하지말고 테스트별로 따로 추가하라. +## ⚪ ️ 1.9 테스트 데이터를 글로벌로 하지말고 테스트별로 따로 추가하라 :white_check_mark: **이렇게 해라:** 황금률에 따르면(섹션 0), 각 테스트는 커플링을 방지하고 테스트 흐름을 쉽게 추론하기 위해 자체 DB 데이터를 추가하고 실행해야 합니다. 실제로 성능 향상(테스트를 실행하기 전에 DB 데이터를 준비(['테스트 픽스쳐'라고도 합니다](https://en.wikipedia.org/wiki/Test_fixture)))을 위해 이를 위반하는 테스터들이 많습니다. 성능은 실제로 유효한 문제이지만 완화될 수 있습니다(2.2 컴포넌트 테스트 참고). 그러나 테스트 복잡성은 대부분의 다른 고려사항들을 통제해야 하는 고통을 수반합니다. 각 테스트에 필요한 DB 레코드를 명시적으로 추가하고, 해당 데이터에 대해서만 테스트를 수행하십시오. 성능이 중요한 문제가 되는 경우 - 데이터를 변경하지 않는 테스트 모음(예: 쿼리)에 대해서 데이터를 준비하는 형태로 타협할 수 있습니다. @@ -533,7 +535,7 @@ expect(menu).toMatchInlineSnapshot(` ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Jest") - + ```javascript before(() => { // 사이트 및 관리자 데이터를 DB에 추가. 데이터는 어디에 있습니까? 외부에. 외부 JSON 또는 마이그레이션 프레임워크에 @@ -554,7 +556,7 @@ it("사이트 이름을 쿼리할 때, 올바른 사이트 이름을 얻는다."
-### :clap: 올바른 예: 우리는 테스트 내부에만 머물 수 있으며, 각 테스트는 자체 데이터 세트에서 동작합니다. +### :clap: 올바른 예: 우리는 테스트 내부에만 머물 수 있으며, 각 테스트는 자체 데이터 세트에서 동작합니다 ```javascript it("사이트 이름을 업데이트 할 때, 성공을 확인한다.", async () => { @@ -573,7 +575,7 @@ it("사이트 이름을 업데이트 할 때, 성공을 확인한다.", async ()

-## ⚪ ️ 1.10 오류를 catch 하지말고 expect 하십시오. +## ⚪ ️ 1.10 오류를 catch 하지말고 expect 하십시오 :white_check_mark: **이렇게 해라:** 오류를 발생시키는 입력값을 assert 할 때, try-catch-finally를 사용하고 catch 블럭에서 assert 하는게 맞아 보일수도 있습니다. 아래 예는 테스트 의도와 결과 expectation을 숨기는 어색하고 장황한 테스트 사례입니다. @@ -593,7 +595,7 @@ it("사이트 이름을 업데이트 할 때, 성공을 확인한다.", async () ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Jest") - + ```javascript it("제품명이 없으면 400 오류를 던진다.", async() => { let errorWeExceptFor = null; @@ -623,7 +625,7 @@ it.only("제품명이 없으면 400 오류를 던진다.", async() => {

-## ⚪ ️ 1.11 테스트에 태깅하십시오. +## ⚪ ️ 1.11 테스트에 태깅하십시오 :white_check_mark: **이렇게 해라:** 다른 테스트는 꼭 다른 시나리오에서 실행해야 합니다: 개발자가 파일을 저장하거나 커밋을 할 때 빠르고, IO가 많이 없는 테스트를 실행해야 합니다. 전체 end-to-end 테스트는 일반적으로 새로운 Pull Request가 제출되었을 때 실행됩니다. 등.. 이러한 경우에 #cold #api #sanity와 같은 키워드로 테스트에 태깅하면 테스트를 효율적으로 grep 할 수 있고, 원하는 하위세트를 호출할 수 있습니다. 예) Mocha를 이용해서 sanity 테스트 그룹만 실행하는 방법입니다: mocha - grep 'sanity' @@ -637,7 +639,7 @@ it.only("제품명이 없으면 400 오류를 던진다.", async() => {
-### :clap: 올바른 예: 테스트를 '#cold-test'로 태깅하면 테스트를 수행하는 사람이 빠른 테스트만 실행할 수 있습니다(IO를 수행하지 않고 개발자가 코딩하는 중에도 자주 실행할 수 있는 테스트 cold === quick). +### :clap: 올바른 예: 테스트를 '#cold-test'로 태깅하면 테스트를 수행하는 사람이 빠른 테스트만 실행할 수 있습니다(IO를 수행하지 않고 개발자가 코딩하는 중에도 자주 실행할 수 있는 테스트 cold === quick) ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") @@ -658,6 +660,7 @@ describe('주문 서비스', function() {

## ⚪ ️ 1.12 일반적인 좋은 테스트 기법들 +  :white_check_mark: **이렇게 해라:** 이 글은 Node.js와 관련이 있거나 최소한 Node.js로 예를 들 수 있는 테스트 조언에 중점을두고 있습니다. 그러나 이번에는 Node.js가 아니지만 잘 알려진 팁들을 포함하고 있습니다. @@ -671,19 +674,19 @@ describe('주문 서비스', function() { # 섹션 2️⃣: 백엔드 테스트 -## ⚪ ️ 2.1 당신의 테스트 포트폴리오를 풍부하게 하십시오: 단위 테스트와 피라미드를 넘어서세요. +## ⚪ ️ 2.1 당신의 테스트 포트폴리오를 풍부하게 하십시오: 단위 테스트와 피라미드를 넘어서세요 :white_check_mark: **이렇게 해라:** 10년이 넘은 모델인 [테스트 피라미드](https://martinfowler.com/bliki/TestPyramid.html)는 세 가지 테스트 유형을 제시하고 대다수 개발자의 테스트 전략에 영향을 주는 훌륭한 모델입니다. 동시에, 몇 가지 반짝이는 새로운 테스트 기술들이 등장하였지만 모두 테스트 피라미드의 그림자 뒤로 사라졌습니다. 우리가 최근 10년간 보아 온 극적인 기술의 변화들(Microservices, cloud, serverless)을 고려할 때, 아주 오래된 모델 하나가 *모든* 어플리케이션 유형에 적합하다는 것이 가능한가요? 테스트 세계는 새로운 기술을 받아들이는 것을 고려하지 않나요? 오해는 하지 마세요. 2019 테스트 피라미드에서 TDD와 단위 테스트는 여전히 강력한 기술이고 아마도 많은 어플리케이션에 가장 어울리는 기술입니다. 다른 모델과 마찬가지로, 테스트 미라미드는 유용하지만 [그것이 항상 맞는 것은 아닙니다](https://en.wikipedia.org/wiki/All_models_are_wrong). 예를 들어, 어떤 IOT 어플리케이션을 생각해 봅시다. 이 어플리케이션은 다수의 이벤트를 Kafka/RabbitMQ 같은 메세지 버스로 보내고 다시 데이터 웨어하우스로 흘려보냅니다. 그리고 이 데이터들은 어떤 분석 UI에서 조회됩니다. 우리는 정말 우리의 테스트 예산의 50%를 통합 중심적(intergration-centric)이고 로직이 거의 없는 어플리케이션의 단위 테스트를 작성하는데 할애해야 할까요? 어플리케이션 유형들이 다양해질 수록(bots, crypto, Alexa-skills) 테스트 피라미드가 적합하지 않은 시나리오들을 발견할 가능성이 커집니다. -지금이 당신의 테스트 포트폴리오를 넓히고 더 많은 테스트 유형들에 익숙해질 시간입니다. (다음 항목에서 몇 가지 아이디어들을 제안합니다.) 테스트 피라미드 같은 모델들도 염두에 둘 뿐만 아니라 당신이 직면하고 있는 현실 세계의 문제들에 적합한 테스트 유형들을 찾으세요. ("우리 API 깨졌어. Consumer-driven contract 테스트 작성하자!" 처럼요.) 위험성 분석을 기반으로 포르폴리오를 구축하는 투자자처럼 당신의 테스트를 다양화하세요 - 문제가 발생할 수 있는 부분을 가늠하고 잠재적 위험성을 줄일 수 있는 예방 방법을 찾으세요. +지금이 당신의 테스트 포트폴리오를 넓히고 더 많은 테스트 유형들에 익숙해질 시간입니다. (다음 항목에서 몇 가지 아이디어들을 제안합니다.) 테스트 피라미드 같은 모델들도 염두에 둘 뿐만 아니라 당신이 직면하고 있는 현실 세계의 문제들에 적합한 테스트 유형들을 찾으세요. ("우리 API 깨졌어. Consumer-driven contract 테스트 작성하자!" 처럼요.) 위험성 분석을 기반으로 포르폴리오를 구축하는 투자자처럼 당신의 테스트를 다양화하세요 - 문제가 발생할 수 있는 부분을 가늠하고 잠재적 위험성을 줄일 수 있는 예방 방법을 찾으세요. 주의 사항 : 소프트웨어 세계에서의 TDD 논쟁은 전형적인 잘못된 이분법입니다. 어떤 사람들은 TDD를 모든 곳에 적용하라고 주장하지만, 다른 일부는 TDD를 악마라고 생각합니다. 절대적으로 한쪽만 주장하는 사람들은 모두 틀렸습니다 :]
-❌ **그렇지 않으면:** 당신은 굉장한 ROI를 주는 몇 가지 툴들을 놓칠 것입니다. Fuzz, lint, mutation 테스트들은 단 10분만에 당신에게 가치를 제공할 수 있습니다. +❌ **그렇지 않으면:** 당신은 굉장한 ROI를 주는 몇 가지 툴들을 놓칠 것입니다. Fuzz, lint, mutation 테스트들은 단 10분만에 당신에게 가치를 제공할 수 있습니다.
@@ -703,15 +706,14 @@ describe('주문 서비스', function() {

-## ⚪ ️2.2 컴포넌트 테스트가 최선의 방법일 수 있다. +## ⚪ ️2.2 컴포넌트 테스트가 최선의 방법일 수 있다 :white_check_mark: **이렇게 해라:** 각각의 단위 테스트는 어플리케이션의 매우 작은 부분만을 커버하고 전체를 모두 커버하기에는 비용이 많이 듭니다. 반면에, end-to-end 테스트는 간단하게 많은 부분을 커버할 수 있지만 깊이가 얕고 더 느립니다. 그렇다면 균형 잡힌 접근법을 적용하여 단위 테스트보다는 크지만 end-to-end 테스트보다는 작은 테스트를 작성하는 것은 어떨까요? 컴포넌트 테스트는 테스트 세계에서 잘 알려지지 않은 방법입니다. - 컴포넌트 테스트는 다음의 두 가지 이점을 모두 제공합니다: 합리적인 성능과 TDD 패턴을 적용할 수 있는 가능성 + 현실적이면서 훌륭한 커버리지 -컴포넌트 테스트는 마이크로 서비스 '단위'에 중점을 두고 API에 대하여 동작합니다. 마이크로서비스 그 자체에 속한 것들 (예를들면, 실제 DB 또는 해당 DB의 인-메모리 버전)은 모킹(Mock)하지 않고, 다른 마이크로서비스 호출과 같은 외부적인 것은 스텁(Stub)합니다. 그렇게 함으로써 우리는 우리가 배포하는 것을 테스트하고 어플리케이션의 바깥쪽에서 안쪽으로 접근하며, 적당한 시간 안에서 큰 자신감을 얻을 수 있습니다. +컴포넌트 테스트는 마이크로 서비스 '단위'에 중점을 두고 API에 대하여 동작합니다. 마이크로서비스 그 자체에 속한 것들 (예를들면, 실제 DB 또는 해당 DB의 인-메모리 버전)은 모킹(Mock)하지 않고, 다른 마이크로서비스 호출과 같은 외부적인 것은 스텁(Stub)합니다. 그렇게 함으로써 우리는 우리가 배포하는 것을 테스트하고 어플리케이션의 바깥쪽에서 안쪽으로 접근하며, 적당한 시간 안에서 큰 자신감을 얻을 수 있습니다.
- -❌ **그렇지 않으면:** 시스템 커버리지가 20%에 불과하다는 것을 깨닫기까지 단위 테스트를 작성하는 데 오랜 시간이 걸릴 수 있습니다. +❌ **그렇지 않으면:** 시스템 커버리지가 20%에 불과하다는 것을 깨닫기까지 단위 테스트를 작성하는 데 오랜 시간이 걸릴 수 있습니다.
@@ -730,15 +732,14 @@ describe('주문 서비스', function() {

-## ⚪ ️2.3 신규 릴리즈가 API 사용을 깨지게 하지 마십시오. +## ⚪ ️2.3 신규 릴리즈가 API 사용을 깨지게 하지 마십시오 -:white_check_mark: **이렇게 해라:** 당신의 마이크로서비스는 다수의 클라이언트를 가지고 있고 호환성의 이유로 여러 버전의 서비스를 운영합니다 (모든 사람을 만족시키기 위해서). 그런 상황에서 당신이 일부 필드를 변경하면 이 필드를 믿고 사용하던 일부 중요한 클라이언트는 화가 날 것입니다. 이것은 통합(integration) 세계에서 해결하기 어려운 진퇴양난에 놓인 문제입니다: 서버 사이드가 여러 클라이언트들의 모든 기댓값을 고려하는 것은 매우 어려운 일입니다. - 반면에, 서버가 릴리즈 날짜를 결정하기 때문에 클라이언트는 어떠한 테스트도 수행할 수 없습니다. -[소비자 주도 계약 테스트(Consumer-driven contracts)와 PACT 프레임워크](https://docs.pact.io/)는 매우 파괴적인 방법으로 이러한 프로세스를 표준화하기 위해 나타났습니다. - 서버가 서버의 테스트 계획을 결정하지 않고, 클라이언트가 서버의 테스트를 결정합니다! PACT는 클라이언트의 기댓값을 기록하여 "브로커"라는 공유된 위치에 올려둘 수 있습니다. 그러면 서버는 그 기댓값을 당겨 받을 수 있고 빌드할 때마다 PACT 라이브러리를 사용하여 깨진 계약(contract - 충족되지 않은 클라이언트의 기댓값)을 감지할 수 있습니다. 이렇게 함으로써, 모든 서버-클라이언트 API 간 일치하지 않은 것들을 빌드/CI 환경에서 조기에 잡을 수 있고 당신의 큰 절망감을 줄여줄 수 있을 것입니다. +:white_check_mark: **이렇게 해라:** 당신의 마이크로서비스는 다수의 클라이언트를 가지고 있고 호환성의 이유로 여러 버전의 서비스를 운영합니다 (모든 사람을 만족시키기 위해서). 그런 상황에서 당신이 일부 필드를 변경하면 이 필드를 믿고 사용하던 일부 중요한 클라이언트는 화가 날 것입니다. 이것은 통합(integration) 세계에서 해결하기 어려운 진퇴양난에 놓인 문제입니다: 서버 사이드가 여러 클라이언트들의 모든 기댓값을 고려하는 것은 매우 어려운 일입니다. - 반면에, 서버가 릴리즈 날짜를 결정하기 때문에 클라이언트는 어떠한 테스트도 수행할 수 없습니다. +[소비자 주도 계약 테스트(Consumer-driven contracts)와 PACT 프레임워크](https://docs.pact.io/)는 매우 파괴적인 방법으로 이러한 프로세스를 표준화하기 위해 나타났습니다. - 서버가 서버의 테스트 계획을 결정하지 않고, 클라이언트가 서버의 테스트를 결정합니다! PACT는 클라이언트의 기댓값을 기록하여 "브로커"라는 공유된 위치에 올려둘 수 있습니다. 그러면 서버는 그 기댓값을 당겨 받을 수 있고 빌드할 때마다 PACT 라이브러리를 사용하여 깨진 계약(contract - 충족되지 않은 클라이언트의 기댓값)을 감지할 수 있습니다. 이렇게 함으로써, 모든 서버-클라이언트 API 간 일치하지 않은 것들을 빌드/CI 환경에서 조기에 잡을 수 있고 당신의 큰 절망감을 줄여줄 수 있을 것입니다.
- -❌ **그렇지 않으면:** 대안은 수동 배포나 배포에 대한 두려움을 안고 가는 것 뿐입니다. +❌ **그렇지 않으면:** 대안은 수동 배포나 배포에 대한 두려움을 안고 가는 것 뿐입니다.
@@ -746,30 +747,24 @@ describe('주문 서비스', function() {
-### :clap: 올바른 예: +### :clap: 올바른 예 ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") - -![alt text](assets/bp-14-testing-best-practices-contract-flow.png ) +![alt text](assets/bp-14-testing-best-practices-contract-flow.png )
- -

- -## ⚪ ️ 2.4 당신의 미들웨어를 독립적으로 테스트 하십시오. +## ⚪ ️ 2.4 당신의 미들웨어를 독립적으로 테스트 하십시오 :white_check_mark: **Do:** 많은 사람들은 미들웨어(Middleware) 테스트를 피합니다. 왜냐하면 미들웨어 테스트는 시스템의 작은 부분일 뿐이고 라이브 Express 서버가 필요하기 때문입니다. 하지만 두 가지 이유 모두 틀렸습니다. - 미들웨어는 작지만 모든 요청 또는 대부분의 요청에 영향을 미치고, {req,res} JS 객체를 가지는 순수한 함수로 쉽게 테스트할 수 있기 때문입니다. 미들웨어 함수를 테스트하기 위해서는 단지 함수를 불러오고 함수가 올바르게 동작하는 것을 확인하기 위해 {req, res} 객체에 대한 인터렉션을 스파이(spy)([예를들어 Sinon을 사용](https://www.npmjs.com/package/sinon))하면 됩니다. 라이브러리 [node-mock-http](https://www.npmjs.com/package/node-mocks-http)는 더 나아가서 행위에 대한 스파이와 함께 {req, res} 객체도 테스트할 수 있습니다. 예를 들어, response 객체의 http 상태가 기대했던 값과 일치하는지 여부를 확인(assert)할 수 있습니다. (아래 예제를 보세요)
- ❌ **Otherwise:** Express 미들웨어에서의 버그 === 모든 요청 또는 대부분의 요청에서의 버그 -
코드 예제 @@ -803,49 +798,42 @@ test('헤더에 인증정보가 없는 요청은, http status 403을 리턴해
- - -

-## ⚪ ️2.5 정적 분석 도구를 사용하여 측정하고 리팩토링 하십시오. -:white_check_mark: **이렇게 해라:** 정적 분석 도구를 사용하면 코드 품질을 개선하고 코드를 유지 관리할 수 있는 객관적인 방법을 제공할 수 있습니다. 정적 분석 도구를 당신의 CI 빌드에 추가하여 코드 냄새(code smell)가 발견되면 중단되도록 할 수 있습니다. 정적 분석 도구가 일반적인 린트(lint) 도구보다 더 좋은 점은 여러 파일들의 컨텍스트 안에서 품질을 검사하고(예: 중복 탐지), 고급 분석(예: 코드 복잡성)을 할 수 있으며 코드 이슈에 대한 히스토리와 프로세스를 추적할 수 있다는 것입니다. 사용할 수 있는 정적 분석 도구 두 가지는 [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube))와 [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate))입니다. +## ⚪ ️2.5 정적 분석 도구를 사용하여 측정하고 리팩토링 하십시오 + +:white_check_mark: **이렇게 해라:** 정적 분석 도구를 사용하면 코드 품질을 개선하고 코드를 유지 관리할 수 있는 객관적인 방법을 제공할 수 있습니다. 정적 분석 도구를 당신의 CI 빌드에 추가하여 코드 냄새(code smell)가 발견되면 중단되도록 할 수 있습니다. 정적 분석 도구가 일반적인 린트(lint) 도구보다 더 좋은 점은 여러 파일들의 컨텍스트 안에서 품질을 검사하고(예: 중복 탐지), 고급 분석(예: 코드 복잡성)을 할 수 있으며 코드 이슈에 대한 히스토리와 프로세스를 추적할 수 있다는 것입니다. 사용할 수 있는 정적 분석 도구 두 가지는 [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube))와 [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate))입니다. Credit:: [Keith Holliday](https://github.com/TheHollidayInn)
- ❌ **그렇지 않으면:** 코드 품질이 좋지 않으면 버그와 성능은 빛나는 새 라이브러리나 최신 기능으로 해결할 수 없는 문제가 될 것입니다. -
코드 예제
-### :clap: 올바른 예: 복잡도가 높은 함수를 찾아내는 상용 도구인 CodeClimate: +### :clap: 올바른 예: 복잡도가 높은 함수를 찾아내는 상용 도구인 CodeClimate ![](https://img.shields.io/badge/🔧%20Example%20using%20Code%20Climate-blue.svg "Examples with CodeClimate") - + ![alt text](assets/bp-16-yoni-goldberg-quality.png " CodeClimat, a commercial tool that can identify complex methods:")
- - -

-## ⚪ ️ 2.6 노드 혼돈(chaos)대한 준비상태를 확인하십시오. +## ⚪ ️ 2.6 노드 혼돈(chaos)대한 준비상태를 확인하십시오 + :white_check_mark: **이렇게 해라:** 이상하게도 대부분의 소프트웨어 테스트는 오직 로직과 데이터를 대상으로 합니다. 하지만 최악의 상황(정말 해결하기 어렵기도 한 상황) 중 일부는 인프라 이슈입니다. 예를 들어, 프로세스 메모리가 과부하 되거나 서버/프로세스가 죽는 상황, 또는 API 속도가 50% 아래로 떨어질 때 모니터링 시스템이 인식하는 상황에 대해서 테스트한 적이 있나요? 이러한 문제 상황들을 테스트하고 줄이기 위해서 - [카오스 엔지니어링(Chaos engineering)](https://principlesofchaos.org/)이 넷플릭스에 의해 탄생했습니다. 카오스 엔지니어링은 혼돈(chaos) 상황에 대한 어플리케이션의 복원력을 테스트하기 위해서 상황에 대한 인식, 프레임워크, 툴들을 제공하는 것을 목표로 합니다. 예를 들어, 유명한 툴 중에 하나인 [카오스 몽키(chaos monkey)](https://github.com/Netflix/chaosmonkey)는 서버를 무작위로 종료시키고 이러한 상황에도 사용자는 서비스를 계속 사용할 수 있어 시스템이 단일 서버에 의존하지 않고 있다는 것을 테스트합니다. (쿠버네티스 버전인 [kube-monkey](https://github.com/asobti/kube-monkey)는 팟(Pod)을 종료시킴) 이러한 툴들은 모두 호스팅/플랫폼 레벨에서 동작합니다. 하지만 당신이 순수 노드 혼돈을 테스트하고 발생시키고 싶으면 어떻게 해야 할까요? 예를 들면, 노드 프로세스가 어떻게 잡히지 않은 오류, 처리되지 않은 프로미스 거부(promise rejection), 최대로 허용된 1.7GB에 대한 v8 메모리 과부하를 처리하는지. 혹은 이벤트 루프가 자주 차단될 때 UX가 만족스럽게 유지되는지 여부 같은 것들이요. 이 문제를 해결하기 위해 제가 모든 종류의 노드 관련된 카오스 행위를 제공하는 [node-chaos](https://github.com/i0natan/node-chaos-monkey) (alpha)를 만들었습니다.
- -❌ **그렇지 않으면:** 탈출구는 없습니다. 머피의 법칙은 자비없이 당신의 시스템에 타격을 줄 것입니다. +❌ **그렇지 않으면:** 탈출구는 없습니다. 머피의 법칙은 자비없이 당신의 시스템에 타격을 줄 것입니다.
@@ -853,19 +841,20 @@ Credit::
-## ⚪ ️2.7 글로벌한 초기 테스트 데이터 집합을 만들지 말고 각 테스트 마다 데이터를 추가하십시오. +## ⚪ ️2.7 글로벌한 초기 테스트 데이터 집합을 만들지 말고 각 테스트 마다 데이터를 추가하십시오 + :white_check_mark: **이렇게 해라:** 황금률(섹션 0)에 따르면 각 테스트는 커플링을 방지하고 테스트 흐름에 대해서 쉽게 추론하기 위해 자신의 DB 데이터들을 추가하고 해당 데이터로 테스트되어야 합니다. 하지만 현실 세계에선 성능 향상을 위해 테스트를 실행하기 전에 초기 데이터를 DB에 추가하는(‘test fixture’라고 알려져 있음) 테스터들에 의해서 이 규칙은 종종 깨지곤 합니다. 성능은 실제로 중요한 문제입니다. - 이 문제는 완화될 수 있습니다 ('컴포넌트 테스트' 섹션을 보세요). 하지만 테스트 복잡성은 대부분의 다른 고려사항들을 지배해 버리는 더욱 고통스런 문제입니다. 실질적으로 각 테스트 케이스에 필요한 DB 레코드만 명시적으로 추가하고 해당 레코드를 가지고만 테스트하세요. 만약 성능이 중요한 문제라면 - 데이터를 변경하지 않는 테스트들에 대해서만 초기 데이터를 채우는 형태로 타협할 수 있습니다. (예: 쿼리)
- -❌ **그렇지 않으면:** 테스트가 실패하고 배포는 중단되어 팀원들은 지금 소중한 시간을 할애해야 합니다. 버그가 있습니까? 찾아봅시다, 오 이런 - 두 개의 테스트가 동일한 테스트 데이터(seed data)를 변경한 것으로 보입니다. +❌ **그렇지 않으면:** 테스트가 실패하고 배포는 중단되어 팀원들은 지금 소중한 시간을 할애해야 합니다. 버그가 있습니까? 찾아봅시다, 오 이런 - 두 개의 테스트가 동일한 테스트 데이터(seed data)를 변경한 것으로 보입니다.
@@ -873,11 +862,11 @@ Credit::
{ // DB에 사이트와 어드민 데이터를 추가합니다. 데이터는 어디에 있나요? 외부에 있습니다. 외부 json 파일이나 마이그레이션 프레임워크에 있습니다. @@ -896,9 +885,10 @@ it("사이트 이름으로 조회했을때, 해당 사이트를 가져온다", a }); ``` +
-### :clap: 올바른 예: 테스트 안에서만 머물며 각 테스트는 자신의 데이터 세트 안에서만 동작합니다. +### :clap: 올바른 예: 테스트 안에서만 머물며 각 테스트는 자신의 데이터 세트 안에서만 동작합니다 ```javascript it("사이트 이름을 변경하면, 성공 결과값을 받아온다", async () => { @@ -922,12 +912,10 @@ it("사이트 이름을 변경하면, 성공 결과값을 받아온다", async ( :white_check_mark: **이렇게 해라:** 컴포넌트 로직을 테스트할때, 화면의 세부사항들은 제외되어야할 노이즈가 됩니다. 그것을 제외함으로써 당신의 테스트들은 순수한 데이터에 집중할 수 있습니다. 실제로, 그래픽 구현에 너무 결합되지 않는 추상적인 방법을 통해 요구되어지는 데이터를 마크업으로부터 추출하십시오. 그리고 느리게 만드는 애니메이션들을 제외한 오직 순수한 데이터를 검증하십시오(vs HTML/CSS 화면 세부사항). 당신은 렌더링하는 것을 피하고 오직 화면의 뒷부분(서비스, 액션, 스토어등과 같은)만을 테스트 하려고 할 수도 있습니다. 하지만, 이것은 실제와 같지도 않으며 심지어 화면에 올바른 데이터가 도달하지 않은 경우를 나타내지도 않는 가짜 테스트에서의 결과가 될 것 입니다. -
❌ **그렇지 않으면:** 당신의 테스트의 순수하게 계산된 데이터는 10ms 내에 준비될수도 있지만, 전체 테스트는 화려하고 불필요한 애니메이션 때문에 500ms(100 테스트 = 1분) 동안 지속될 것 입니다. -
코드 예제 @@ -962,6 +950,7 @@ test('오직 VIP를 보기위해 사용자목록을 표시했을때, 오직 VIP
### :thumbsdown: 잘못된 예: 화면 세부사항들과 데이터를 섞어서 검증 + ```javascript test('오직 VIP를 보기위해 사용자목록을 표시했을때, 오직 VIP 멤버들만 보여져야 한다', () => { // Arrange @@ -981,12 +970,8 @@ test('오직 VIP를 보기위해 사용자목록을 표시했을때, 오직 VIP
- - -

- ## ⚪ ️ 3.2 변하지 않은 요소들에 기반해서 HTML 엘리먼트들을 찾으십시오 :white_check_mark: **이렇게 해라:** CSS 검색자들과 다르게 양식 레이블들과 같이 그래픽 변경에도 살아남을 요소들을 기반으로 HTML 엘리먼트들을 찾으십시오. 만약 설계된 엘리먼트가 이와 같은 요소들을 가지고 있지 않다면, 'test-id-submit-button' 과 같이 테스트에 한정된 요소를 만드십시오. 이 방법은 당신의 기능/로직 테스트들이 룩앤필때문에 절대 망가지지 않을 것을 보장할 뿐만 아니라, 이 엘리먼트와 요소가 테스트에 의해 사용되어지고 제거되어서는 안된다는것을 팀 전체에게 명확하게 합니다. @@ -1005,7 +990,7 @@ test('오직 VIP를 보기위해 사용자목록을 표시했을때, 오직 VIP ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") - + ```html // the markup code (part of React component)

@@ -1032,6 +1017,7 @@ test('오직 VIP를 보기위해 사용자목록을 표시했을때, 오직 VIP
### :thumbsdown: 잘못된 예: CSS 요소들에 의존 + ```html {value} @@ -1046,12 +1032,8 @@ test('데이터가 전달되지 않으면, 0을 보여준다', () => { }); ``` - - - -
## ⚪ ️ 3.3 가능한한, 실제와 같고 완전히 렌더링된 컴포넌트를 테스트하십시오 @@ -1075,7 +1057,7 @@ test('데이터가 전달되지 않으면, 0을 보여준다', () => { ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") - + ```javascript class Calendar extends React.Component { static defaultProps = {showFilters: false} @@ -1107,6 +1089,7 @@ test('실제적인 접근: 필터들을 클릭하면, 필터들이 화면에 표 ``` ### :thumbsdown: 잘못된 예: 얕은 렌더링과 함께 실제를 목킹 + ```javascript test('얕은/목킹 접근: 필터들을 클릭하면, 필터들이 화면에 표시된다', () => { @@ -1128,15 +1111,13 @@ test('얕은/목킹 접근: 필터들을 클릭하면, 필터들이 화면에
- ## ⚪ ️ 3.4 슬립을 사용하지 마십시오. 프레임워크에서 비동기 이벤트들을 위해 지원하는 내장 기능을 사용하십시오. 그리고 속도를 높이려 노력하십시오 -:white_check_mark: **이렇게 해라:** 대부분의 경우에 테스트 완료시간은 알 수 없습니다. (예: 애니메이션은 요소의 출현을 지연시킴) - 이런 경우에는 슬립(예: setTimeout)을 피하고, 대부분의 플랫폼들이 제공하는 더 결정적인 메소드들을 사용하십시오. 몇몇 라이브러리들은 awaiting 기능을 허용합니다. (예: [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), 대기를 위한 다른 API [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). 때때로, 더 우아한 방법은 API같이 느린 자원을 스텁하는 것입니다. 그런 후 응답순간이 결정적이 되면, 컴포넌트를 명시적으로 다시 렌더링 할 수 있습니다. 외부 컴포넌트가 슬립상태일때는, [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks)가 유용할 수 있습니다. 슬립은 당신의 테스트를 느리고 위험하게 만들기 때문에 피해야할 패턴입니다(너무 짧은 시간 기다려야할 경우). 만약 슬립과 폴링이 필연적이고 테스트 프레임워크의 지원이 없다면, [wait-for-expect](https://www.npmjs.com/package/wait-for-expect)와 같은 라이브러리들이 준결정 솔루션으로서 도움을 줄 수도 있습니다. +:white_check_mark: **이렇게 해라:** 대부분의 경우에 테스트 완료시간은 알 수 없습니다. (예: 애니메이션은 요소의 출현을 지연시킴) - 이런 경우에는 슬립(예: setTimeout)을 피하고, 대부분의 플랫폼들이 제공하는 더 결정적인 메소드들을 사용하십시오. 몇몇 라이브러리들은 awaiting 기능을 허용합니다. (예: [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), 대기를 위한 다른 API [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). 때때로, 더 우아한 방법은 API같이 느린 자원을 스텁하는 것입니다. 그런 후 응답순간이 결정적이 되면, 컴포넌트를 명시적으로 다시 렌더링 할 수 있습니다. 외부 컴포넌트가 슬립상태일때는, [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks)가 유용할 수 있습니다. 슬립은 당신의 테스트를 느리고 위험하게 만들기 때문에 피해야할 패턴입니다(너무 짧은 시간 기다려야할 경우). 만약 슬립과 폴링이 필연적이고 테스트 프레임워크의 지원이 없다면, [wait-for-expect](https://www.npmjs.com/package/wait-for-expect)와 같은 라이브러리들이 준결정 솔루션으로서 도움을 줄 수도 있습니다.
❌ **그렇지 않으면:** 오랜 시간동안 슬립하는 경우, 테스트는 더 느려질 것 입니다. 슬립할때, 테스트중인 유닛이 제 시간에 반응하지 않으면 테스트는 실패할 것 입니다. 그래서 그것은 테스트가 실패하는 약점과 나쁜 성능간의 트레이드 오프를 가지게 됩니다. -
코드 예제 @@ -1176,6 +1157,7 @@ test('movie title appears', async () => { ``` ### :thumbsdown: 잘못된 예: 사용자 정의 슬립 코드 + ```javascript test('movie title appears', async () => { @@ -1199,7 +1181,6 @@ test('movie title appears', async () => {
-
## ⚪ ️ 3.5 화면의 내용이 네트워크를 통해 어떻게 제공될지 확인하십시오 @@ -1221,13 +1202,11 @@ test('movie title appears', async () => { ![](/assets/lighthouse2.png "Lighthouse page load inspection report") - -
-## ⚪ ️ 3.6 백엔드 API와 같이 자주 멈출 수 있거나 느린 리소스는 stub 하십시오. +## ⚪ ️ 3.6 백엔드 API와 같이 자주 멈출 수 있거나 느린 리소스는 stub 하십시오 :white_check_mark: **이렇게 해라:** 주요 기능에 대한 테스트 코드(E2E테스트 아님) 작성 시, backend API 처럼 그 기능의 주 역할에서 벗어나는 항목은 제외할 수 있도록 stub(예: test double) 하십시오. 실제 네트워크를 호출하지 말고, test double 라이브러리([Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble))를 사용하십시오. 이 경우 가장 큰 장점은 예상치 못한 테스트 실패를 예방 할 수 있습니다. 코드단에서 API 정의에 따라 test를 적용하는 작업은 안정적이지 않고 당신의 component는 문제가 없지만 수시로 test가 실패 할 수 있습니다.(운영 상태의 env 설정은 testing에서는 사용하지 마세요. API 요청에 병목이 발생 할 수 있습니다.) 이런식으로 해서 API 응답 데이터가 없는 경우, 에러가 응답되는 경우 등의 다양한 API 상태에 따른 테스트를 진행 할 수 있습니다. 다시한번 강조하지만 실제 네트워크 호출은 test를 매우 느리게 만들것입니다. @@ -1235,7 +1214,6 @@ test('movie title appears', async () => { ❌ **그렇지 않으면:** 평균 테스트 실행 시간이 몇 ms 인 경우, API 호출로 개당 최소 100ms 시간이 걸리게 되고 테스트는 약 20배 느려지게 됩니다. -
코드 예제 @@ -1243,10 +1221,11 @@ test('movie title appears', async () => {
### :clap: 올바른 예: Stubbing 하거나 API 응답값 변조 + ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with react-testing-library") - + ```javascript // unit under test @@ -1285,7 +1264,7 @@ test('products가 없는 경우, 적절한 메시지 표시하기', () => {
-## ⚪ ️ 3.7 전체 시스템에 걸친 엔드-투-엔드 테스트가 거의 없습니다. +## ⚪ ️ 3.7 전체 시스템에 걸친 엔드-투-엔드 테스트가 거의 없습니다 :white_check_mark: **이렇게 해라:** E2E(end-to-end)는 일반적으로 실제 브라우저를 사용한 UI를 위한 테스트를 의미하지만(3.6 참고), 다른 의미로 실제 백엔드를 포함하여 전체 시스템을 확장하는 테스트를 의미합니다. 후자의 테스트 유형은 교환 스키마에 대한 잘못된 이해로 인해 발생할 수 있는 프론트엔드와 백엔드간의 통합 버그를 커버하기 때문에 상당히 유용합니다. 또한 백엔드간 통합 문제(예 : 마이크로서비스 A가 마이크로서비스 B에 잘못된 메시지를 보낸다)를 발견하고 배포 실패를 감지하는 효과적인 방법입니다. [Cypress](https://www.cypress.io)와 [Pupeteer](https://github.com/GoogleChrome/puppeteer)같은 UI 프레임워크만큼 친숙하고 성숙한 E2E 테스트 백엔드 프레임워크는 없습니다. 이러한 테스트의 단점은 구성 요소가 많은 환경을 구성하는 데 드는 높은 비용과 주로 불안정성 입니다 - 50개의 마이크로서비스가 제공되는데, 하나가 실패하더라도 전체 E2E가 실패. 따라서 이 기법을 적절히 사용해야 하며, 그 중 1~10개 정도만 사용해야 합니다. 즉, 소수의 E2E 테스트 일지라도 배포 및 통합 오류와 같은 유형의 문제를 잡을 수 있습니다. 프로덕션과 같은 스테이징 환경에서 실행하는 것이 좋습니다. @@ -1357,8 +1336,10 @@ beforeEach(setUser => () {
### :clap: 올바른 예: 모든 페이지의 smoke 탐색하기 + ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + ```javascript it('모든 페이지를 smoke 테스트 할때, 페이지들이 정상적으로 로드 되어야 한다', () => { // Cypress를 이용한 예제 입니다 @@ -1374,7 +1355,6 @@ it('모든 페이지를 smoke 테스트 할때, 페이지들이 정상적으로
-
## ⚪ ️ 3.10 다같이 협업가능한 문서로 테스트 내용을 내보내기 하십시오 @@ -1392,6 +1372,7 @@ it('모든 페이지를 smoke 테스트 할때, 페이지들이 정상적으로 ### :clap: 올바른 예: cucumber-js 의 humnan 언어를 사용한 테스트 코드 ![](https://img.shields.io/badge/🔨%20Example%20using%20Cocumber-blue.svg "Examples using Cucumber") + ```javascript // Cucumber 를 사용하여 테스트를 설명: 평문을 사용하여 누구든 이해하고 협업 할 수 있다 @@ -1413,14 +1394,9 @@ Feature: Twitter new tweet ![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") - - - - -## ⚪ ️ 3.11 자동화된 툴을 사용하여 시각적 문제(Visual Issues)를 감지해라. - +## ⚪ ️ 3.11 자동화된 툴을 사용하여 시각적 문제(Visual Issues)를 감지해라 :white_check_mark: **이렇게 해라:** 컨테츠가 겹치거나 깨지는 등의 시각적 문제들이 감지될 때, UI 스크린 샷을 캡처하기 위해 자동화 도구를 셋업하세요. 이를 통해, 올바른 데이터가 준비 될 뿐만 아니라 사용자가 편리하게 변경을 확인할 수 있습니다. 이러한 기술은 현재 널리 채택되지는 않았습니다. 우리의 테스트 사고 방식은 여전히 기능 테스트에 의존하지만 사용자가 실제로 경험하는 것은 시각적 요소이며 다양한 디바이스 유형때문에 일부 UI 버그들은 간과되기 쉽습니다. 일부 무료 툴들은 육안 검사를 위한 스크린 샷을 생성하거나 저장하는 기능과 같은 기본적인 기능들을 제공합니다. 이 방법은 작은 크기의 App에는 충분하지만, 변경이 발생할 때마다 사람의 손길이 필요한 다른 수동 테스트를 수행하기에는 제약이 있습니다. 반면에, 명확한 정의가 없기 때문에 UI 문제를 자동으로 감지하는 것은 상당히 어려운 일입니다. - 이 부분이 Visual Regression 테스트 영역입니다. 이전 버전의 UI를 최근 변경과 비교하여 차이점을 감지하여 문제를 해결합니다. 일부 오픈소스/무료 툴들은 이 기능들의 일부를 제공해 주지만(예. [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](https://github.com/HuddleEng/PhantomCSS)) 상당한 셋업 시간이 필요합니다. 상용 툴들은(예. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) 설치가 간편하고 관리 UI, 알람, ‘시각적 노이즈(예. 광고, 애니메이션)’를 제거하는 스마트 캡쳐와 문제를 일으키는 DOM/css의 근본 원인을 분석하는 고급 기능들을 제공합니다. @@ -1428,7 +1404,6 @@ Feature: Twitter new tweet ❌ **Otherwise:** How good is a content page that display great content (100% tests passed), loads instantly but half of the content area is hidden? -
코드 예제 @@ -1441,7 +1416,6 @@ Feature: Twitter new tweet
- ### :clap: Doing It Right Example: Configuring wraith to capture and compare UI snapshots ![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg @@ -1521,28 +1495,21 @@ cy.eyesCheckWindow('mark as completed'); }); ``` - - -
- -

- # 섹션 4️⃣: 테스트 효과 측정

-## ⚪ ️ 4.1 자신감을 갖기에 충분한 커버리지를 확보하십시오. ~80%가 이상적인 것 같습니다. +## ⚪ ️ 4.1 자신감을 갖기에 충분한 커버리지를 확보하십시오. ~80%가 이상적인 것 같습니다 :white_check_mark: **이렇게 해라:** 테스트의 목적은 빠른 변경에 대한 충분한 자신감을 갖기 위한 것입니다. 분명히 더 많은 코드가 테스트 될수록 팀은 더 자신감을 가질 수 있습니다. 커버리지는 얼마나 많은 라인(브랜치, 구문(statements) 등)이 테스트에 의해 커버되었는지에 대한 지표입니다. 그렇다면 어느 정도가 충분할까요? 10–30%는 빌드 정확성에 대해 판단하기에는 분명히 너무 낮습니다. 반면에 100%는 비용이 많이 들고 정작 당신의 관심을 중요한 부분이 아닌 테스트 코드로 옮겨버릴지도 모릅니다. 이것에 대한 답은 수치는 어플리케이션 유형과 같은 다양한 요소들에 따라 달라진다는 것입니다. - 만약 당신이 Airbus A380의 차세대 버전을 만들면 100%로 맞춰야 하지만 웹툰 사이트라면 50%면 충분합니다. 비록 테스트에 열성인 대부분의 사람들은 적절한 커버리지 임계값이 상황에 따라 달라져야 한다고 하지만, 그들 중 대부분은 대다수의 어플리케이션을 만족하기 위해서 경험상으로 80%([마틴 파울러: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html))가 적절하다고 얘기합니다. 구현 팁: 당신의 CI 환경에서 커버리지 임계치를 설정하여 그 기준에 미치지 못하면 빌드를 멈추도록 하고 싶을 것입니다. (컴포넌트 당 임계치를 설정하는 것도 가능합니다. 아래 예제 코드를 보세요). 이 위에, 빌드 커버리지 감소에 대한 감지도 고려해 보세요. (새로 커밋 된 코드가 커버리지에 못 미칠 때) - 이렇게 함으로써 개발자들이 커버리지를 올리거나 적어도 유지하도록 압박할 수 있습니다. 말한대로 커버리지는 오직 하나의 양적 지표일 뿐 테스트의 견고성을 나타내기에는 충분하지 않습니다. 그리고 다음 항목에 나와있는 것처럼 당신을 속일 수 있습니다.
- ❌ **그렇지 않으면:** Confidence and numbers go hand in hand, without really knowing that you tested most of the system — there will also be some fear. and fear will slow you down
@@ -1568,9 +1535,9 @@ cy.eyesCheckWindow('mark as completed');

-## ⚪ ️ 4.2 커버리지 리포트를 확인하여 테스트 되지 않은 부분과 기타 이상한 점들을 감지하십시오. +## ⚪ ️ 4.2 커버리지 리포트를 확인하여 테스트 되지 않은 부분과 기타 이상한 점들을 감지하십시오 -:white_check_mark: **이렇게 해라:** 일부 문제들은 레이더망 아래로 숨어버려 기존의 툴들을 사용하여 찾기 매우 어렵습니다. 이것들은 실제로 버그는 아니지만 심각한 영향을 줄 수 있는 생각지 못 한 어플리케이션 동작들입니다. 예를 들어, 일부 코드 영역은 절대 또는 거의 호출되지 않습니다. - ‘PricingCalculator’라는 상품 가격을 설정하는 클래스가 있다고 생각해 보세요. DB에 100000개의 상품이 있고 판매도 많지만 이 클래스는 실제로 절대 호출되지 않는 것으로 밝혀졌습니다... 코드 커버리지 리포트를 통해 어플리케이션이 당신이 원하는 대로 동작하는지 확인할 수 있습니다. 그 외에도 리포트는 어떤 코드들이 테스트되지 않았는지를 강조해서 보여줄 수도 있습니다. - 코드의 80%가 테스트 되었다는 알림이 중요한 부분이 커버되었는지에 대한 여부를 나타내진 않습니다. 리포트를 만드는 것은 쉽습니다. - 운영 또는 테스트를 할 때 커버리지 트래킹을 하면서 어플리케이션을 실행하세요. 그러고 나서 각 코드 영역이 얼마나 자주 호출됐는지를 나타내는 형형색색의 리포트를 보세요. 잠깐 시간을 내서 이 데이터들을 보면 몇 가지 문제점들을 발견하게 될 수도 있습니다. +:white_check_mark: **이렇게 해라:** 일부 문제들은 레이더망 아래로 숨어버려 기존의 툴들을 사용하여 찾기 매우 어렵습니다. 이것들은 실제로 버그는 아니지만 심각한 영향을 줄 수 있는 생각지 못 한 어플리케이션 동작들입니다. 예를 들어, 일부 코드 영역은 절대 또는 거의 호출되지 않습니다. - ‘PricingCalculator’라는 상품 가격을 설정하는 클래스가 있다고 생각해 보세요. DB에 100000개의 상품이 있고 판매도 많지만 이 클래스는 실제로 절대 호출되지 않는 것으로 밝혀졌습니다... 코드 커버리지 리포트를 통해 어플리케이션이 당신이 원하는 대로 동작하는지 확인할 수 있습니다. 그 외에도 리포트는 어떤 코드들이 테스트되지 않았는지를 강조해서 보여줄 수도 있습니다. - 코드의 80%가 테스트 되었다는 알림이 중요한 부분이 커버되었는지에 대한 여부를 나타내진 않습니다. 리포트를 만드는 것은 쉽습니다. - 운영 또는 테스트를 할 때 커버리지 트래킹을 하면서 어플리케이션을 실행하세요. 그러고 나서 각 코드 영역이 얼마나 자주 호출됐는지를 나타내는 형형색색의 리포트를 보세요. 잠깐 시간을 내서 이 데이터들을 보면 몇 가지 문제점들을 발견하게 될 수도 있습니다.
❌ **그렇지 않으면:** 어떤 코드가 테스트되지 않았는지 알 수 없으면 문제의 원인도 알 수 없습니다. @@ -1581,7 +1548,7 @@ cy.eyesCheckWindow('mark as completed');
-### :thumbsdown: 올바르지 않은 예: 이 커버리지 리포트에는 어떤 문제가 있나요? 현실 세계 시나리오로 QA에서 어플리케이션 사용을 추적했고 흥미로운 로그인 패턴을 찾았습니다. (힌트: 로그인 실패 횟수가 비례하지 않습니다. 분명히 무언가 잘못되었습니다.) 마침내 일부 프론트엔드 버그가 백엔드 로그인 API를 계속 호출하고 있다는 것이 밝혀졌습니다. +### :thumbsdown: 올바르지 않은 예: 이 커버리지 리포트에는 어떤 문제가 있나요? 현실 세계 시나리오로 QA에서 어플리케이션 사용을 추적했고 흥미로운 로그인 패턴을 찾았습니다. (힌트: 로그인 실패 횟수가 비례하지 않습니다. 분명히 무언가 잘못되었습니다.) 마침내 일부 프론트엔드 버그가 백엔드 로그인 API를 계속 호출하고 있다는 것이 밝혀졌습니다 ![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report? based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) @@ -1632,7 +1599,7 @@ it("Test addNewOrder, don't use such test names", () => {
-### :clap: 올바른 예: mutation 테스트 도구인 Stryker 보고서는 테스트 되지 않은 코드의 양을 감지하고 계산합니다. +### :clap: 올바른 예: mutation 테스트 도구인 Stryker 보고서는 테스트 되지 않은 코드의 양을 감지하고 계산합니다 ![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "mutation 테스트 도구인 Stryker 보고서는 테스트 되지 않은 코드의 양을 감지하고 계산합니다.") @@ -1654,7 +1621,7 @@ it("Test addNewOrder, don't use such test names", () => {
-### :thumbsdown: 올바르지 않은 예: 오류로 가득 찬 테스트 케이스, 운 좋게도 린터가 잡았습니다. +### :thumbsdown: 올바르지 않은 예: 오류로 가득 찬 테스트 케이스, 운 좋게도 린터가 잡았습니다 ```javascript describe("Too short description", () => { @@ -1692,7 +1659,7 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test
-### :thumbsdown: 올바르지 않은 예: 잘못된 Error 객체가 실수로 throw되어 이 오류에 대한 stack trace가 나타나지 않습니다. 운 좋게도 ESLint는 다음과 같은 프로덕션 버그를 잡아냅니다. +### :thumbsdown: 올바르지 않은 예: 잘못된 Error 객체가 실수로 throw되어 이 오류에 대한 stack trace가 나타나지 않습니다. 운 좋게도 ESLint는 다음과 같은 프로덕션 버그를 잡아냅니다 ![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "잘못된 Error 객체가 실수로 throw되어 이 오류에 대한 stack trace가 나타나지 않습니다. 운 좋게도 ESLint는 다음과 같은 프로덕션 버그를 잡아냅니다.") @@ -1716,7 +1683,7 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test
-### :clap: 올바른 예: 코드 품질 검사를 수행하는 npm 스크립트는 요청 시 또는 개발자가 새 코드를 푸시하려고 할 때 모두 병렬로 실행됩니다. +### :clap: 올바른 예: 코드 품질 검사를 수행하는 npm 스크립트는 요청 시 또는 개발자가 새 코드를 푸시하려고 할 때 모두 병렬로 실행됩니다 ```javascript "scripts": { @@ -1785,7 +1752,7 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test

-## ⚪ ️ 5.5 라이센스 및 표절을 검사하여 법적 문제를 피하십시오. +## ⚪ ️ 5.5 라이센스 및 표절을 검사하여 법적 문제를 피하십시오 :white_check_mark: **이렇게 해라:** 라이센싱과 표절 문제는 당장 당신의 주요 관심사가 아닐 수 있지만, 10분 안에 이 내용을 확인하지 않으시겠습니까? 많은 npm 패키지의 [라이센스 체크](https://www.npmjs.com/package/license-checker) 및 [표절 확인](https://www.npmjs.com/package/plagiarism-checker)(상용 도구의 무료 플랜)을 CI 파이프라인에 쉽게 포함시킬 수 있습니다. 그리고 제한적인 라이센스의 종속성이나 Stack Overflow에서 복사하여 붙여넣은 일부 저작권을 위반한 것으로 보이는 코드를 점검하십시오. @@ -1797,7 +1764,7 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test
-### :clap: 올바른 예: +### :clap: 올바른 예 ```javascript //install license-checker in your CI environment or also locally @@ -1857,7 +1824,7 @@ license-checker --summary --failOn BSD
-### :clap: 올바른 예: 코드가 최신 버전보다 어느정도 뒤쳐지는지 감지하기 위하여 [ncu](https://www.npmjs.com/package/npm-check-updates)를 수동으로 또는 CI 파이프라인 내에서 사용할 수 있습니다. +### :clap: 올바른 예: 코드가 최신 버전보다 어느정도 뒤쳐지는지 감지하기 위하여 [ncu](https://www.npmjs.com/package/npm-check-updates)를 수동으로 또는 CI 파이프라인 내에서 사용할 수 있습니다 ![alt text](assets/bp-27-yoni-goldberg-npm.png "코드가 최신 버전보다 어느정도 뒤쳐지는지 감지하기 위하여 ncu를 수동으로 또는 CI 파이프라인 내에서 사용할 수 있습니다.") @@ -1885,7 +1852,7 @@ license-checker --summary --failOn BSD

-## ⚪ ️ 5.9 빌드 매트릭스: 여러 노드 버전을 사용해서 동일한 CI 단계를 실행 하십시오. +## ⚪ ️ 5.9 빌드 매트릭스: 여러 노드 버전을 사용해서 동일한 CI 단계를 실행 하십시오 :white_check_mark: **이렇게 해라:** 품질 검사는 [세런디피티](https://ko.wikipedia.org/wiki/%EC%84%B8%EB%9F%B0%EB%94%94%ED%94%BC%ED%8B%B0)에 관한 것으로, 문제를 조기에 발견하는데 도움이 되는 더 많은 기회를 제공합니다. 재사용 가능한 패키지를 개발하거나 다양한 구성 및 노드 버전으로 여러 고객의 제품을 실행하는 경우, CI는 모든 구성의 순열에 대해 테스트 파이프 라인을 실행해야합니다. 예를 들어, 일부 고객은 MySQL을 사용하고 다른 고객은 PostgreSQL을 사용한다고 가정합시다. 일부 CI 벤더는 '매트릭스'라는 기능을 제공하여 MySQL, PostgreSQL 및 8, 9, 10과 같은 여러 노드 버전의 모든 순열에 대해 테스트를 실행할 수 있습니다. 이 경우에는 어떠한 추가 노력없이 구성(설정)만을 사용하여 가능합니다(테스트 또는 기타 품질 검사가 있다고 가정). 매트릭스를 지원하지 않는 다른 CI는 확장이나 조정이 필요할 수 있습니다. @@ -1893,14 +1860,13 @@ license-checker --summary --failOn BSD ❌ **그렇지 않으면:** So after doing all that hard work of writing testing are we going to let bugs sneak in only because of configuration issues? -
예제 코드
-### :clap: 올바른 예: Travis(CI 벤더) 빌드 정의를 사용하여 여러 노드 버전에 대한 동일한 테스트를 실행하십시오. +### :clap: 올바른 예: Travis(CI 벤더) 빌드 정의를 사용하여 여러 노드 버전에 대한 동일한 테스트를 실행하십시오
language: node_js
node_js:
- "7"
- "6"
- "5"
- "4"
install:
- npm install
script:
- npm run test
@@ -1939,7 +1905,7 @@ license-checker --summary --failOn BSD
-## [Bruno Scheufler](https://github.com/BrunoScheufler) +## [Bruno Scheufler](https://github.com/BrunoScheufler) **Role:** 기술 검토 및 고문 diff --git a/readme.md b/readme.md index f5123694..bf8386ce 100644 --- a/readme.md +++ b/readme.md @@ -6,8 +6,6 @@
- - # 👇 Why this guide can take your testing skills to the next level
@@ -744,7 +742,7 @@ Learn and practice [TDD principles](https://www.sm-cloud.com/book-review-test-dr ## ⚪ ️2.1 Enrich your testing portfolio: Look beyond unit tests and the pyramid -:white_check_mark: **Do:** The [testing pyramid](https://martinfowler.com/bliki/TestPyramid.html), though 10> years old, is a great and relevant model that suggests three testing types and influences most developers’ testing strategy. At the same time, more than a handful of shiny new testing techniques emerged and are hiding in the shadows of the testing pyramid. Given all the dramatic changes that we’ve seen in the recent 10 years (Microservices, cloud, serverless), is it even possible that one quite-old model will suit *all* types of applications? shouldn’t the testing world consider welcoming new testing techniques? +:white_check_mark: **Do:** The [testing pyramid](https://martinfowler.com/bliki/TestPyramid.html), though 10> years old, is a great and relevant model that suggests three testing types and influences most developers’ testing strategy. At the same time, more than a handful of shiny new testing techniques emerged and are hiding in the shadows of the testing pyramid. Given all the dramatic changes that we’ve seen in the recent 10 years (Microservices, cloud, serverless), is it even possible that one quite-old model will suit _all_ types of applications? shouldn’t the testing world consider welcoming new testing techniques? Don’t get me wrong, in 2019 the testing pyramid, TDD and unit tests are still a powerful technique and are probably the best match for many applications. Only like any other model, despite its usefulness, [it must be wrong sometimes](https://en.wikipedia.org/wiki/All_models_are_wrong). For example, consider an IoT application that ingests many events into a message-bus like Kafka/RabbitMQ, which then flow into some data-warehouse and are eventually queried by some analytics UI. Should we really spend 50% of our testing budget on writing unit tests for an application that is integration-centric and has almost no logic? As the diversity of application types increase (bots, crypto, Alexa-skills) greater are the chances to find scenarios where the testing pyramid is not the best match. @@ -817,7 +815,7 @@ Component tests focus on the Microservice ‘unit’, they work against the API,
-### :clap: Doing It Right Example: +### :clap: Doing It Right Example ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") @@ -883,7 +881,7 @@ Credit:
{ :white_check_mark: **Do:** When checking integrations, go beyond the happy and sad paths. Check not only errored responses (e.g., HTTP 500 error) but also network-level anomalies like slow and timed-out responses. This will prove that the code is resilient and can handle various network scenarios like taking the right path after a timeout, has no fragile race conditions, and contains a circuit breaker for retries. Reputable interceptor tools can easily simulate various network behaviors like hectic service that occasionally fail. It can even realize when the default HTTP client timeout value is longer than the simulated response time and throw a timeout exception right away without waiting -
❌ **Otherwise:** All your tests pass, it's only the production who will crash or won't report errors correctly when 3rd parties send excpetional responses @@ -1107,7 +1104,6 @@ beforeEach(() => {
- ## ⚪ ️2.13 Test the five potential outcomes :white_check_mark: **Do:** When planning your tests, consider covering the five typical flow's outputs. When your test is triggering some action (e.g., API call), a reaction is happening, something meaningful occurs and calls for testing. Note that we don't care about how things work. Our focus is on outcomes, things that are noticeable from the outside and might affect the user. These outcomes/reactions can be put in 5 categories: @@ -1933,7 +1929,7 @@ The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for
-### :clap: Doing It Right Example: +### :clap: Doing It Right Example ```javascript //install license-checker in your CI environment or also locally