← Regresar a lecciones
  • Jest

  • react native

  • mobile development

  • testing

  • monitoring

  • quality-assurance

Testing y Monitoreo en React Native

Testing en React Native: ¿Qué significa probar una app?
  • Tipos de testing en React Native

Cuando construyes una aplicación móvil, el verdadero reto no es escribir código, es asegurar que funcione bien hoy, mañana y después de futuras modificaciones. Sin testing ni monitoreo, ocurre que cada cambio en el código es un riesgo, los bugs llegan a producción sin que te des cuenta, dependes del usuario final para saber si algo falló.

Por otro lado con una estrategia adecuada de pruebas y monitoreo podemos, detectar errores antes de que lleguen al usuario, reducir costos de mantenimiento y soporte, como tambien tomar decisiones informadas con datos reales del funcionamiento de la app.

Testing = prevención Monitoreo = detección y análisis

Y ambos son complementarios.

Testing en React Native: ¿Qué significa probar una app?

Probar significa verificar que el código hace lo que debería hacer, de manera consistente y sin efectos inesperados. Cuando no hay pruebas automatizadas, la única forma de validar cambios es entrar a la app, navegar, tocar botones y esperar no romper nada. Esto es costoso, lento y muy poco confiable.

Con testing automatizado:

  • Cada vez que haces un cambio, los tests validan que no hayas roto una funcionalidad previa.
  • Puedes refactorizar código sin miedo.
  • La calidad sube y los tiempos de desarrollo bajan.

Tipos de testing en React Native

Tipo de testObjetivoHerramientaEjemplo de uso
UnitarioValidar lógica puraJestverificar cálculos, validaciones, formateo de datos
De componentes (UI)Validar comportamientos de pantallaReact Native Testing Libraryverificar que un botón incremente un contador
IntegraciónValidar interacción entre módulosJest + mocksvalidar que un componente llame correctamente a un servicio

Regla clave: los tests deben validar comportamientos, no implementaciones.

Ejemplo: Test unitario con Jest

Primero, algo simple: una función que calcula el total de una compra.

1// utils/calculateTotal.ts 2export const calculateTotal = (price: number, qty: number) => price * qty;

Creemos un test que valide ese comportamiento:

1// __tests__/calculateTotal.test.ts 2import { calculateTotal } from "../utils/calculateTotal"; 3 4test("calcula correctamente el total", () => { 5 expect(calculateTotal(10, 3)).toBe(30); 6});

Con este test garantizas que si alguien cambia esa función o su comportamiento, serás alertado inmediatamente.

Ejemplo: Test de un componente con React Native Testing Library

Aquí no probamos cómo está hecho el componente, sino lo que hace cuando el usuario interactúa.

1// components/Counter.tsx 2import React, { useState } from "react"; 3import { Button, Text } from "react-native"; 4 5export const Counter = () => { 6 const [count, setCount] = useState(0); 7 8 return ( 9 <> 10 <Text testID="count-label">{count}</Text> 11 <Button title="Incrementar" onPress={() => setCount(count + 1)} /> 12 </> 13 ); 14};

Test:

1// __tests__/Counter.test.tsx 2import React from "react"; 3import { render, fireEvent } from "@testing-library/react-native"; 4import { Counter } from "../components/Counter"; 5 6test("incrementa el contador al presionar", () => { 7 const { getByText, getByTestId } = render(<Counter />); 8 9 fireEvent.press(getByText("Incrementar")); 10 11 expect(getByTestId("count-label").props.children).toBe(1); 12});

Qué estamos validando:

  • que el botón esté visible
  • que al presionarlo ocurra un cambio real en la UI
  • que ese cambio sea el esperado

Monitoreo en producción: logging estructurado

Aunque los tests previenen errores, ningún sistema está libre de fallas en producción. Por lo tanto, necesitas saber qué pantalla se estaba usando cuando falló, qué acción ejecutó el usuario, qué datos estaban en juego; ahí entra el logging estructurado.

❌ Logging tradicional

1console.log("User logged in", user);

Problemas:

  • produce mensajes desordenados
  • no permite analizar patrones o eventos
  • difícil de filtrar

✅ Logging estructurado (recomendado)

1console.log(JSON.stringify({ 2 event: "USER_LOGIN", 3 userId: user.id, 4 timestamp: Date.now(), 5}));

Ventajas:

  • cada log tiene estructura y contexto
  • fácil de filtrar por tipo de evento

Wrapper para logging

1// utils/logger.ts 2export const logEvent = (event: string, payload = {}) => { 3 console.log(JSON.stringify({ event, payload, timestamp: Date.now() })); 4};

Uso:

1logEvent("API_REQUEST", { endpoint: "/products" });

Este patrón permite centralizar la responsabilidad del logging.

Buenas prácticas

Una de las dudas más frecuentes al comenzar a testear en React Native es: “¿Debo testear todo mi código?”. La respuesta es no, testear no significa replicar cada componente o línea de código, significa proteger las partes del sistema que, si fallan, afectan directamente al usuario o al negocio.

A continuación se desarrollan cuatro buenas prácticas esenciales aplicadas específicamente a proyectos con React Native CLI.

  1. Testear la lógica que pueda romper la app: En React Native, la mayor parte de las decisiones importantes no se toman en los componentes, sino en:

    • funciones auxiliares (utils/)
    • hooks de negocio (hooks/)
    • servicios y controladores (services/)

Esa lógica suele ser independiente de la UI, lo que facilita testearla sin necesidad del renderizado de una pantalla.

1// utils/formatCurrency.ts 2export const formatCurrency = (amount: number) => `$${amount.toFixed(2)}`;

Test unitario:

1test("formatea un número a moneda", () => { 2 expect(formatCurrency(10)).toBe("$10.00"); 3});

¿Por qué importa? Si alguien modifica esta función en el futuro (por ejemplo, para soportar otra moneda), un test evitará que introduzca un error sin querer.

  1. Empezar por casos críticos del flujo de usuario: No empieces por componentes simples como botones o estilos.Comienza por lo que afecta objetivos de negocio o bloquea el uso de la app.

Casos típicos en una app móvil:

Caso críticoRiesgo si fallaQué testear
LoginEl usuario no puede usar la appValidación de formularios, llamadas al backend
Procesos de compra/pagoPérdidas económicasCálculos, totales, métodos de pago
Formularios con reglasMal funcionamiento del flujoMensajes de error y estados del botón

Esto te da cobertura del 80% del riesgo con 20% de esfuerzo.

  1. Usar logging estructurado para monitorear en producción: En desarrollo (__DEV__) vemos la consola, pero en producción la app corre dentro de un dispositivo al que no tenemos acceso. Por eso, los logs deben ser estructurados, consistentes y con contexto.

❌ Ejemplo incorrecto:

1console.log("Error en el login");

Ejemplo recomendado (JSON estructurado):

1logEvent("LOGIN_FAILED", { 2 email, 3 reason: error.message, 4});

Este formato permite:

  • enviar logs a servicios como Sentry, Datadog o Firebase Crashlytics,
  • filtrar por evento,
  • entender qué hizo el usuario cuando ocurrió el error.

Implementación mínima en React Native CLI:

1// utils/logger.ts 2export const logEvent = (event: string, payload = {}) => { 3 const log = { event, payload, timestamp: Date.now() }; 4 5 if (__DEV__) { 6 console.log(JSON.stringify(log, null, 2)); 7 } else { 8 // producción → enviar a un proveedor externo 9 // Sentry.captureMessage(JSON.stringify(log)); 10 } 11};
  1. Evita usar console.log sin estructura

En React Native CLI, la calidad de la app no solo depende de lo bien que esté desarrollada, sino de lo bien que puedas saber cuándo algo deja de funcionar, el testing asegura que tu app funciona como debe y el monitoreo asegura que sabrás cuando deje de hacerlo. Una app profesional requiere ambos.