Las condiciones de carrera se encuentran entre algunos de los problemas más desafiantes de detectar y reproducir. Como tal, representan un desafío significativo en el desarrollo, notablemente en la interfaz de usuario. En esta charla, exploramos cómo detectar condiciones de carrera aprovechando las técnicas de fuzzing. Te guiamos a través del descubrimiento del verdadero problema de las condiciones de carrera y cómo impactan en la experiencia del usuario. Te proporcionamos herramientas y ejemplos que demuestran cómo detectarlas fácilmente en tu trabajo diario gracias a las pruebas que se basan en el fuzzing. Después de esta charla, esperamos que tu código React esté libre de condiciones de carrera o al menos que tengas las herramientas adecuadas para ayudarte.
Rompe la Carrera: Detección Fácil de Condiciones de Carrera para React
Video Summary and Transcription
Las condiciones de carrera pueden ser complejas de depurar y reproducir, causando frustración para los usuarios. El orador discute ejemplos de condiciones de carrera y formas de solucionarlas y evitarlas. Demuestran un ejemplo de un campo de autocompletado en React y cómo manejar las condiciones de carrera en las llamadas API. El orador introduce el marco FastCheck para pruebas basadas en propiedades para abordar las condiciones de carrera y mejorar las pruebas. La aleatorización de entradas y salidas puede ayudar a descubrir errores específicos para ciertos escenarios. El orador también discute la mitigación de las condiciones de carrera en React y el manejo de la sobrecarga de pruebas y la reproducibilidad.
1. Introducción a la Condición de Carrera
Hoy, hablaré sobre la condición de carrera. La condición de carrera es compleja de depurar y reproducir. Sucede inesperadamente y puede ser frustrante para los usuarios. Daré ejemplos y discutiré formas de solucionar y evitar las condiciones de carrera. Soy Nicolas, el autor de la biblioteca Fasttech y el fundador de Pigment.
Buenas tardes a todos. Hoy, hablaré sobre la condición de carrera. Mi nombre es Nicolas y la idea es abordar un problema que es complejo de debug, complejo para reproducir, y es por eso que quería discutir la condición de carrera. Porque básicamente, la condición de carrera resulta ser un poco así. Nunca sabes cuándo sucede y probablemente Oh, lo siento. No se suponía que fuera eso. Nunca sabes cuándo sucede y tienes que lidiar con ellos. Pero nos centraremos en la condición de carrera. Aquí hay un ejemplo de condición de carrera. En el pasado, hace unos años, estaba buscando alojamiento en París para ir a París. En el famoso sitio web, no estoy vinculado en absoluto a esta empresa, pero estaba buscando alojamiento en París, y en algún momento, cambié de opinión. Decidí ir a Londres. Puedes ver que estaba buscando alojamiento en Londres. Hay algunos alojamientos bonitos en Londres, y parecen bastante agradables, de hecho. Pero en algún momento, obtuve algunos resultados de París. Esto es exactamente de lo que trata la condición de carrera. Es como algo que pides en algún momento, pero sucede un poco tarde, y recibes resultados más tarde. En algún momento, el usuario se frustra un poco al obtener este resultado. En ese caso específico, es solo una mala UX para el usuario. Ellos lidiarán con eso, y aún podrán usar la aplicación. Pero eso no está bien. Daré algunos ejemplos adicionales para eso. Pero hoy, el objetivo será hablar sobre estas condiciones de carrera y encontrar algunas formas juntos para solucionarlas y evitar que sean una fuente de frustración para los usuarios.
Entonces, como me presenté rápidamente antes, avancemos un poco más. Soy Nicolas. Como se presentó, soy el autor de la biblioteca llamada Fasttech. Puedes tener el enlace allí. Puedes encontrarme en las redes sociales. Pero hablaré un poco sobre mi empresa. Mi empresa es
2. Entendiendo las Condiciones de Carrera
Estoy haciendo planificación de negocios y quería hablar sobre las condiciones de carrera. Las condiciones de carrera son importantes para tratar, especialmente en finanzas donde las cifras precisas son cruciales. Una condición de carrera ocurre cuando el comportamiento del sistema depende del tiempo de eventos incontrolables. En una aplicación frontal o React, las entradas de los usuarios y las llamadas a la API son fuentes potenciales de condiciones de carrera. Para ilustrar, volvamos a visitar un video donde busqué estancias en París y cambié de opinión. Las llamadas a la API para París y Londres no devolvieron resultados en el orden esperado, causando una interfaz de usuario defectuosa.
3. Ejemplo de Campo de Autocompletado en React
Me centraré en un ejemplo muy sencillo de un campo de autocompletado escrito en React. El usuario escribe una consulta y el campo devuelve resultados a medida que escriben. Propondré una implementación ingenua utilizando React y dos estados. El primer estado es la consulta, que se utiliza para llenar una entrada. Cuando el usuario hace cambios en la entrada, se llama a una función llamada actualizar consulta, que establece el estado. Hay un caso especial para la cadena vacía.
4. Manejo de Llamadas API y Pruebas
En este caso específico, restablezco las sugerencias a vacío y llamo a la API con la nueva consulta del usuario. Una vez que obtengo el resultado, actualizo el estado de las sugerencias y las renderizo en el componente. Para evitar condiciones de carrera, podemos probar manualmente la entrada o escribir pruebas. Escribí una prueba simple utilizando Jest y la biblioteca de pruebas de React. La prueba simula la API y filtra los resultados en función de la consulta del usuario. Asegura que el resultado será 'banana' y ejecuta el componente.
5. Ejecutando la Prueba y Manejando Condiciones de Carrera
Ejecuto el campo de autocompletado con la API simulada y emulo la escritura del usuario. Me aseguro de que las sugerencias mostradas sean las esperadas y que el número de llamadas a la API coincida con la longitud de la consulta. La prueba pasa, pero la implementación ingenua no maneja las condiciones de carrera. Ilustro el problema con una línea de tiempo donde las llamadas a la API pueden resolverse en desorden.
6. Entendiendo el Orden de Resolución de Promesas
En segundo lugar, si la primera consulta se resuelve al final, el usuario verá resultados que no coinciden con la consulta. Esto puede compararse con escribir 'París' y obtener resultados para 'Londres'. Es importante abordar este problema ya que puede ocurrir fácilmente en el mundo real debido a factores como el equilibrio de carga y el almacenamiento en caché. Veamos lo que pasamos por alto en nuestra prueba original y lo que encontramos. Creamos una línea de tiempo donde cambiar el orden de los resultados causó el problema. Para solucionar esto, necesitamos cambiar el orden en el que se resuelven las promesas. Presentamos FastCheck.
7. Uso del Marco FastCheck para Llamadas API
Soy el autor y principal contribuyente de FastCheck, un marco de pruebas basado en propiedades. Veamos cómo podemos usarlo. Definimos una propiedad que toma generadores y una función lambda para afirmaciones. Ejecutamos la propiedad utilizando los ayudantes de propiedad y afirmación. Confiamos en el marco para manejar las llamadas API de manera determinista.
8. Conectando el Marco y Encontrando Errores
Y cuando entrará es como cuando le dije que lo hiciera. Es la línea 20. Para conectar el marco, tuve que definir algún tipo de propiedad. La propiedad está hecha de generadores y la función lambda, que es la forma de ejecutar la prueba en sí. El resultado está hecho de un contraejemplo. El marco decidió que el orden no debería ser como el que recibimos inicialmente, sino que intentará algo más. Informa que no funciona. Es un marco de pruebas basado en propiedades similar al fuzzing.
9. Mejorando la Prueba y Manejando Eventos Incontrolables
Hoy, discutiré cómo mejorar la prueba permitiendo que el marco decida los resultados esperados, la consulta del usuario y el resultado generado. Al precalcular los resultados y permitir que el marco elija la consulta, podemos manejar diferentes escenarios. Además, en lugar de codificar los resultados, podemos generar valores aleatorios. Este enfoque considera al usuario como un evento incontrolable y prueba el código con la escritura del usuario, la resolución de consultas y la escritura del usuario nuevamente.
10. Actualizando la Prueba y Descubriendo Errores
Actualizamos nuestra prueba permitiendo que el marco decida la consulta válida del usuario, los resultados y el orden. El marco prueba diferentes escenarios e identifica un caso fallido. Al probar varias entradas de usuario, podemos descubrir errores específicos para ciertas cadenas.
11. Abordando las Condiciones de Carrera y Aleatorizando las Entradas
Las condiciones de carrera rompen la confianza del usuario en su aplicación. Reordenar las promesas puede ayudar a solucionarlas, pero es fácil pasar por alto el problema real. Aleatorizar la salida y las entradas es una solución. La biblioteca Fastcheck, utilizada por Jest y Jasmine, puede ayudar a identificar las condiciones de carrera en React.
12. Equilibrando el Enfoque Metódico con la Aleatorización
Tengo una pregunta sobre la aleatorización de la resolución de promesas. ¿Cómo equilibras la necesidad de ser metódico con la aleatorización? El marco permite sembrar el algoritmo, haciendo que las pruebas sean reproducibles. Además, hay una lógica de reducción para simplificar los casos fallidos y reducir la complejidad.
QnA
Mitigando las Condiciones de Carrera
¡Gracias por las preguntas! La condición de carrera de React que encontré estaba relacionada con suspense y suspense list. Causó un problema de bloqueo donde la lista de suspense no se resolvería. Para mitigar las condiciones de carrera, el enfoque depende del caso. En mi empresa, utilizamos una estrategia de caché para valores disponibles globalmente y actualizaciones en tiempo real. La estabilidad de la salida y la información del backend determinan el enfoque. Aunque puede haber algún parpadeo en la interfaz de usuario, el objetivo es converger a la versión real después de cierto tiempo.
Eso es genial. Muchas gracias por todas las preguntas, gente. Vaya, ahora hay tantas preguntas. Por favor, sigan enviándolas. Pero eso fue rápido. ¿Cuál fue la condición de carrera de React que encontraste? Vaya, buena pregunta. Fue algo alrededor de React. Fue con suspense, suspense list y cosas así. Había algún tipo de orden en el que, dada la resolución de tus suspenses, si estabas en la lista de suspense en algún tipo de modo hacia adelante o cosas así, que todavía, no estoy seguro de si el asunto ha sido lanzado aún, pero terminaste en algún tipo de bloqueo y nunca pudiste liberar, quiero decir, la lista de suspense nunca se resolverá en absoluto. Oh, eso es bastante complicado. Siento que esa va a ser una palabra para encapsular algunas de estas historias. ¿Qué enfoques utilizas para mitigar las condiciones de carrera después de haberlas detectado? Para la presentación, no he mostrado cómo podemos solucionarlo en este ejemplo específico. Creo que depende mucho del caso. Personalmente tengo algunos casos en la empresa donde tenemos una estrategia de caché para almacenar algunos valores que están disponibles globalmente en la aplicación y se actualizan en tiempo real. Realmente creo que depende de vez en vez, depende de lo que quieras, de cuán estable quieras que sea tu salida y cuál es la información
Manejo de la Sobrecarga de Pruebas y la Reproducibilidad
En mi caso, la interfaz de usuario puede parpadear un poco, pero siempre convergerá a la versión real. El marco ejecuta la afirmación 100 veces por defecto, permitiéndote reducir o personalizar el número de ejecuciones. La sobrecarga es limitada, ya que el código de generación se mantiene simple. 100 ejecuciones son generalmente suficientes para encontrar muchos errores, pero casos específicos pueden requerir pruebas más frecuentes. Diferentes ejecuciones de un conjunto de pruebas utilizando cadenas aleatorias usarán diferentes cadenas cada vez, facilitando la detección de nuevos errores.
Interesante. Genial. Esta es una gran pregunta. ¿Hay alguna sobrecarga o cuál es la sobrecarga? ¿Puedes controlar esto y cuántas iteraciones o permutaciones deberías o puedes o has generado? Por defecto, el marco simplemente ejecutará 100 veces la afirmación. La idea no es ejecutar todo porque el alcance de las posibilidades es infinito porque estamos pensando en cualquier tipo de consulta de usuario, cualquier tipo de resultado. Así que básicamente, el marco simplemente está diciendo, está bien, probemos 100 de ellos. Si falla, simplemente intentará reducir y la sobrecarga es como si ejecutaras la prueba 100 veces pero puedes reducir eso, puedes cambiar el número de ejecuciones que quieres para tu prueba si lo necesitas. Para la sobrecarga, diría que es el coste de generar el valor pero normalmente, debería ser bastante limitado porque intento no poner tanta complejidad en el código que está haciendo la generación. Quiero decir, la idea es ser lo más libre posible para hacer la generación de cosas pero todavía tiene una sobrecarga.
Si el valor por defecto es 100, ¿100 es un buen número para empezar? ¿Funciona eso en la mayoría de los casos? Sí, inicialmente, me sorprendió un poco cuando empecé a hacer eso. Así que las propiedades basadas en la técnica no están relacionadas con JavaScript en absoluto. Vino de Haskell u otras palabras y básicamente, me sorprendió un poco que 100 ejecuciones pudieran encontrar algo y cuando lo intenté en realidad con 100 ejecuciones, está bastante bien para encontrar muchos errores. Si es un caso muy específico de borde, probablemente no caerás en él en 100 ejecuciones pero en ese caso, tienes algo muy especial para probar y tal vez quieras ejecutarlo más a menudo para lanzarlo en más pruebas. Sí, seguro. Así que 100 se siente bien para muchos casos de uso. Sí, y tendrás tu CI que lo ejecutará, etc. Así que podrás ver. Siento que depende es como una respuesta bastante segura para esta. Sí. Sí, sí, sí. Vale. ¿Las diferentes ejecuciones de un conjunto de pruebas utilizando cadenas aleatorias usarán diferentes cadenas cada vez, como todas las diferentes ejecuciones? Parece que podría ser difícil reproducir los fallos aunque. Esa es una buena pregunta. A menudo me hacen esta. Básicamente, por defecto, estoy diciendo por defecto, para ver esto como si se cambiara todo el tiempo. Así que cada vez que ejecutes la prueba, tendrás una nueva semilla, por lo que significa que se producirán nuevas cadenas. Y posiblemente
Estabilidad y Falsos Positivos en las Pruebas
El marco está diseñado para encontrar casos límite clásicos y no debería ser inestable. Sin embargo, puede haber casos raros en los que falle. Los falsos positivos pueden ocurrir si las condiciones para una carrera son muy raras y dependen de combinaciones específicas de factores.
Sí, es un tema complicado, ¿no es así? Porque no estás ejecutando la suite de pruebas bajo las mismas condiciones exactas cada vez. Hay diferencias. Pero en teoría, son casos razonablemente realistas. Entonces, si falla, ¿qué? Siento que esto está en el mismo ámbito de preguntas, pero ¿existe la posibilidad de que nunca haga una prueba solo siendo un falso positivo, tal vez porque no lo has ejecutado suficientes veces? Sí, puedes tener falsos positivos. Así que básicamente, fusionas algo, sientes que funciona. Por ejemplo, recientemente trabajé en alguna condición de carrera en la caché. Así que la condición
Pruebas con el marco vTest
Al ejecutar pruebas en CI, los falsos positivos pueden identificarse y revertirse rápidamente si la prueba es nueva. Se planteó una pregunta sobre la pronunciación de 'vTest' o 'vitest', y se decidió colectivamente que sería 'vTest'. El código de prueba mostrado se puede usar dentro de las pruebas existentes de Jest sin ninguna vinculación de marco. El orador también mencionó tener vinculaciones para marcos específicos como Jest y vTest, pero no son necesarios si se usa la sintaxis .assert.property.
Sí. Sí. Esta es una pregunta. Ayer, en la masterclass de testing JS Summit, hice este comentario justo al principio donde no sabía si era vTest o vitest. El grupo llegó colectivamente a una decisión, y ahora no puedo recordar cuál es. ¿Funciona bien con vTest? Verás, yo habría optado por defecto por vitest. Y luego porque es VT, ¿no es así? Es VT, así que tiene que ser vTest. Gracias. Sí, definitivamente. No hay vinculación con ningún marco. Entonces básicamente, la prueba que te he mostrado está justo dentro de una prueba existente de Jest. Solo usamos la prueba clásica de Jest. Es solo una construcción dentro de ella. Entonces puedes poner el mismo código exacto dentro de vTest. No sé cómo quieres pronunciarlo. Es vTest. Es vTest. He oído vTest. Y tengo algunas vinculaciones para frameworks específicos. Entonces básicamente, tengo uno para Jest, para que puedas hacer algo como it.props. Para vTest, también tengo uno, pero quiero evolucionarlo un poco con v1. Pero básicamente, normalmente, no deberías necesitar nada. Quiero decir, si estás de acuerdo con escribir .assert.property, funcionará bien.
Ubicación de la Fuente del Marco y Preguntas y Respuestas
¿Este marco ayuda a localizar la fuente de las condiciones? Tenemos una sección de preguntas y respuestas con el orador para conversaciones cara a cara. Por favor, proporciona más información para preguntas sin respuesta. Tenemos un breve descanso antes de continuar.
Check out more articles and videos
We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career
Workshops on related topic
The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.
React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.
Table of contents- The different kinds of React application tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting DOM elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RTL tests and how to handle them
Prerequisites- Familiarity with building applications with React- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Testing Library- Machine setup: Node LTS, Yarn
Tests rely on many conditions and are considered to be slow and flaky. On the other hand - end-to-end tests can give the greatest confidence that your app is working. And if done right - can become an amazing tool for boosting developer velocity.
Detox is a gray-box end-to-end testing framework for mobile apps. Developed by Wix to solve the problem of slowness and flakiness and used by React Native itself as its E2E testing tool.
Join me on this workshop to learn how to make your mobile end-to-end tests with Detox rock.
Prerequisites- iOS/Android: MacOS Catalina or newer- Android only: Linux- Install before the workshop
1. Welcome to Postman- Explaining the Postman User Interface (UI)2. Workspace and Collections Collaboration- Understanding Workspaces and their role in collaboration- Exploring the concept of Collections for organizing and executing API requests3. Introduction to API Testing- Covering the basics of API testing and its significance4. Variable Management- Managing environment, global, and collection variables- Utilizing scripting snippets for dynamic data5. Building Testing Workflows- Creating effective testing workflows for comprehensive testing- Utilizing the Collection Runner for test execution- Introduction to Postbot for automated testing6. Advanced Testing- Contract Testing for ensuring API contracts- Using Mock Servers for effective testing- Maximizing productivity with Collection/Workspace templates- Integration Testing and Regression Testing strategies7. Automation with Postman- Leveraging the Postman CLI for automation- Scheduled Runs for regular testing- Integrating Postman into CI/CD pipelines8. Performance Testing- Demonstrating performance testing capabilities (showing the desktop client)- Synchronizing tests with VS Code for streamlined development9. Exploring Advanced Features - Working with Multiple Protocols: GraphQL, gRPC, and more
Join us for this workshop to unlock the full potential of Postman for API testing, streamline your testing processes, and enhance the quality and reliability of your software. Whether you're a beginner or an experienced tester, this workshop will equip you with the skills needed to excel in API testing with Postman.
We will cover writing tests, covering every application feature, structuring tests, intercepting network requests, and setting up the backend data.
Anyone who knows JavaScript programming language and has NPM installed would be able to follow along.