Probar y medir: configuración local, sandbox y las métricas que importan
Las compras son el único subsistema de una app donde un fallo se traduce directamente en dinero perdido o en usuarios con derecho a reclamar, y sin embargo es el que menos se prueba, porque probarlo parece exigir dinero real. No lo exige: la configuración local de `StoreKit` permite simular un catálogo completo, renovaciones aceleradas, fallos de cobro y reembolsos sin salir de Xcode. Esta lección cubre las tres capas de prueba y termina con las cuatro métricas que de verdad explican si un negocio de suscripción funciona.
Hay una razón estructural por la que las integraciones de compras llegan a producción mal probadas, y no es la pereza: durante años probarlas exigía cuentas especiales, dispositivos dedicados y esperas de días para ver una renovación. El resultado era predecible: se probaba el camino feliz, se enviaba y se descubrían los caminos infelices leyendo los mensajes de los usuarios que habían pagado. Ese mundo terminó cuando la configuración local de StoreKit trajo el catálogo, las renovaciones y los fallos a un archivo del proyecto, ejecutándose contra un servidor simulado dentro de Xcode, con renovaciones cada treinta segundos y un panel para provocar a mano cualquier desgracia. Lo que antes era un ensayo lento y caro es hoy una prueba automatizable, y lo que sigue faltando en la mayoría de los proyectos no es capacidad técnica sino el hábito de tratar la monetización como código que se prueba igual que el resto.
- Construir una configuración local de
StoreKitcon el catálogo completo y usarla en previsualizaciones y pruebas. - Automatizar los caminos infelices con
SKTestSession: fallo de cobro, reembolso, caducidad y compra diferida. - Operar el entorno de pruebas real y conocer sus tiempos acelerados y sus diferencias con producción.
- Elegir y calcular las cuatro métricas que explican la salud de un negocio de suscripción.
Probar sin dinero y sin esperar
El archivo de configuración de StoreKit es un documento del proyecto que describe el catálogo entero: identificadores, precios, grupos de suscripción, ofertas introductorias, localizaciones y niveles. Se asocia a un esquema de ejecución y, mientras está activo, todas las llamadas de la app se resuelven contra un servidor local en lugar de contra la App Store. Eso significa comprar sin cuenta, sin red y sin gastar nada; significa también que las previsualizaciones de SwiftUI pueden mostrar la pantalla de compra con productos reales en lugar de datos falsos escritos a mano, que es la diferencia entre iterar el diseño de la pantalla que más ingresos genera en segundos o en minutos.
El panel de transacciones de Xcode es la otra mitad de la herramienta y la que rara vez se explota. Desde ahí se ajusta la velocidad de renovación —hasta una renovación cada treinta segundos, de modo que un año de vida de un suscriptor cabe en un café—, se fuerza el fallo del próximo cobro, se emite un reembolso, se activa la aprobación diferida para simular una cuenta familiar con permiso parental y se borran todas las compras para volver al estado inicial. Cada una de esas palancas corresponde a un camino que en producción ocurrirá miles de veces y que sin esto casi nadie ha visto nunca.
Renovación acelerada
Un mes en treinta segundos. Permite recorrer prueba, cobro, renovación y caducidad en una sola sesión de depuración.
Fallo de cobro
Provoca la entrada en gracia y en reintento. Es la única forma práctica de comprobar que no expulsas a quien quiere seguir pagando.
Reembolso
Marca la transacción como revocada. Sirve para verificar que tu capa de derechos mira revocationDate de verdad.
Aprobación diferida
Simula el permiso parental. Verifica que el caso pendiente no bloquea la interfaz y que la acreditación llega por la escucha.
Lo que convierte todo esto en ingeniería y no en exploración manual es SKTestSession, la clase del marco de pruebas que expone esas mismas palancas desde el código. Con ella, un caso desagradable deja de ser una anécdota que alguien reprodujo una vez y pasa a ser una prueba que corre en cada integración.
import StoreKitTest
func testElFalloDeCobroNoExpulsaAlUsuarioEnGracia() async throws {
let sesion = try SKTestSession(configurationFileNamed: "Catalogo")
sesion.clearTransactions()
sesion.timeRate = .oneRenewalEveryThirtySeconds
try await sesion.buyProduct(identifier: "pro.mensual")
var derechos = Derechos()
await derechos.recalcular()
XCTAssertTrue(derechos.tieneAccesoPro)
try sesion.expireSubscription(productIdentifier: "pro.mensual")
await derechos.recalcular()
XCTAssertFalse(derechos.tieneAccesoPro)
}
El servidor simulado no valida firmas contra la infraestructura real de Apple, de modo que la verificación siempre tiene éxito y jamás verás el caso no verificado. Tampoco emite notificaciones de servidor, así que la mitad remota de tu integración queda sin ejercitar. Todo lo demás —estados, ofertas, elegibilidad, reembolsos— se comporta igual. Sabiendo esas dos limitaciones, la configuración local cubre con holgura el noventa por ciento del trabajo.
Del simulador al mundo
El entorno de pruebas real es la segunda capa y sigue siendo imprescindible por lo que la primera no cubre: cuentas de Apple auténticas, la hoja de pago verdadera, las notificaciones a tu servidor y el comportamiento de tu backend con datos firmados de verdad. Se usa con cuentas específicas creadas en App Store Connect, y desde iOS 16 se configuran desde los ajustes del sistema sin necesidad de cerrar la sesión principal, lo que eliminó una de las fricciones históricas más molestas del proceso.
Sus tiempos también están comprimidos, con una tabla que conviene tener a mano porque desconcierta al principio: una suscripción mensual renueva cada cinco minutos, una anual cada hora, y toda suscripción se cancela sola tras seis renovaciones consecutivas. Ese último detalle explica el desconcierto clásico de quien cree haber encontrado un fallo cuando su suscripción de prueba desaparece sin motivo aparente.
flowchart LR a[Configuracion local en Xcode] --> b[Pruebas automatizadas con SKTestSession] b --> c[Entorno de pruebas con cuentas reales] c --> d[Notificaciones de servidor hacia tu backend] d --> e[Pruebas externas con usuarios reales] e --> f[Produccion con panel de metricas]
Hay dos diferencias entre el entorno de pruebas y producción que producen incidencias reales y merecen quedar escritas. La primera es que en pruebas no existen los pagos fallidos por falta de fondos, con lo que el reintento de cobro solo se ejercita provocándolo a mano. La segunda es que las notificaciones de servidor llegan a una URL distinta de la de producción, y confundirlas es la causa más frecuente de que un backend recién desplegado no reciba absolutamente nada mientras todo parece correcto en el dispositivo.
La tercera capa es la distribución de prueba externa, y aquí hay una asimetría que sorprende a muchos equipos: las compras en esa fase son gratuitas y usan el entorno de pruebas, de modo que sirven para validar los flujos pero no dicen nada sobre la disposición real a pagar. Cualquier conclusión sobre conversión extraída de ahí es ruido.
Las métricas que importan
Con la integración probada queda la pregunta que decide si el negocio existe, y la mayoría de los paneles la responden mal porque miden lo que es fácil de contar. Los ingresos brutos del mes no son una métrica: mezclan altas nuevas con renovaciones, ignoran los reembolsos, no distinguen entre crecimiento y estancamiento y ni siquiera reflejan lo que se cobra, porque la comisión de la plataforma se lleva un quince o un treinta por ciento según el programa en el que estés. Cuatro indicadores bastan y ninguno de ellos es el número grande de la portada.
El primero es la conversión de prueba a pago, que se calcula sobre cohortes cerradas y nunca sobre el mes natural: de los que empezaron la prueba en marzo, cuántos siguen pagando cuando venció. Mezclar cohortes produce cifras que suben cuando crece la captación y bajan cuando se estanca, con independencia de la calidad del producto, y sobre esa señal es imposible tomar ninguna decisión.
El segundo es la retención por periodo de renovación, medida como porcentaje de suscriptores que llegan a la renovación número uno, dos, tres y seis. Es la métrica más honesta que existe sobre si el producto entrega valor continuo, porque un usuario que renueva cuatro veces ha tomado cuatro veces la decisión de seguir. Su complemento, la tasa de bajas, dice lo mismo desde el otro lado y tiene la virtud de ponerle número a una intuición: con una fuga mensual del cinco por ciento, la vida media de un suscriptor es de veinte meses, y toda la economía del producto se sigue de ahí.
El tercero es el ingreso neto por usuario, calculado después de comisión, después de reembolsos y sobre el total de usuarios activos, no solo sobre los que pagan. Es el número que se compara con el coste de adquisición para saber si el crecimiento construye algo o quema dinero, y es también el que revela que dos apps con la misma facturación pueden tener negocios opuestos.
El cuarto es la tasa de reembolso, que casi nadie vigila y que funciona como un detector de humo excepcional. Una tasa que sube de golpe suele significar una de tres cosas muy concretas: la pantalla de compra promete algo que el producto no cumple, un cambio reciente rompió la entrega del valor, o el precio se percibe como una trampa. En los tres casos el problema es grave y el reembolso lo señala antes que cualquier otra métrica.
Conviene cerrar el nivel con la idea más incómoda de todas, porque es la que separa la instrumentación honesta de la que produce desastres lentos. Toda organización optimiza lo que mide, y esa optimización no se detiene en la frontera de lo legítimo por sí sola; se comporta como cualquier proceso de búsqueda, explorando el espacio de acciones hasta encontrar la que más mueve el número, sea o no la que crea valor. Si el indicador principal son los ingresos del mes, existe una forma trivial de mejorarlo: dificultar la cancelación, esconder el precio real tras una prueba que se convierte sola, presentar la pantalla de pago en un momento en que el usuario no puede evaluar lo que compra. Todo eso funciona, mueve el número hacia arriba durante uno o dos trimestres, y al mismo tiempo aumenta los reembolsos, hunde las valoraciones y erosiona la única cosa que sostiene un negocio de suscripción, que es la disposición de la gente a seguir pagando por voluntad propia. La razón profunda es que el ingreso mensual es un indicador retrasado y agregado, y por tanto es compatible con casi cualquier historia subyacente, incluidas las peores. La retención por renovación, en cambio, es un indicador que solo mejora si el usuario sigue eligiendo quedarse, y no admite atajos: no se puede engañar a alguien para que renueve cinco veces seguidas. Elegir la segunda como métrica de cabecera no es una preferencia estética, es una decisión de gobierno que restringe el espacio de tácticas que el equipo puede permitirse, del mismo modo que una prueba automatizada restringe el espacio de cambios que pueden entrar. La formulación general merece recordarse mucho más allá de la monetización: una métrica es una función objetivo, y toda función objetivo mal elegida acaba siendo explotada, no por mala fe sino por competencia. Escoge la que solo se puede mejorar haciendo bien tu trabajo.
Tres capas: configuración local en Xcode para el catálogo y los caminos infelices, SKTestSession para automatizarlos, y el entorno de pruebas con cuentas reales para lo que el simulador no cubre —firmas auténticas y notificaciones de servidor—. Los tiempos están comprimidos y toda suscripción de prueba muere tras seis renovaciones. Y cuatro métricas bastan: conversión por cohorte, retención por renovación, ingreso neto por usuario y tasa de reembolso. Los ingresos del mes no son una métrica.
- Escribe la configuración local con tu catálogo completo, incluidas ofertas y grupos, y úsala en las previsualizaciones de la pantalla de compra.
- Automatiza con
SKTestSessioncuatro casos: compra correcta, fallo de cobro con gracia, reembolso y compra pendiente por aprobación. - Ejecuta un ciclo completo en el entorno de pruebas con una cuenta real y confirma que tu servidor recibe las notificaciones en la URL correcta.
- Calcula la conversión de prueba a pago de una cohorte cerrada y compárala con la cifra mensual agregada; explica la diferencia.
- Define el panel definitivo con las cuatro métricas, elige cuál será la de cabecera y argumenta qué tácticas quedan descartadas al elegirla.