Skip to content
ArceApps Logo ArceApps
EN

IA + TDD en Android: La Nueva Era del Testing

9 min de lectura
IA + TDD en Android: La Nueva Era del Testing

🐢 La Paradoja del TDD

Todos conocemos la teoría de TDD (Test Driven Development):

  1. Red: Escribe un test que falle.
  2. Green: Escribe el código mínimo para pasar el test.
  3. Refactor: Mejora el código sin romper el test.

La realidad: Es difícil. Requiere mucha disciplina y escribir mucho código de “fontanería” (mocks, setups) antes de escribir una línea de lógica productiva. Por eso es común abandonar este enfoque a medio camino.

Este artículo es la versión completa del original de octubre de 2025. Lo he reescrito tras un año aplicándolo con juniors, viendo dónde funciona, dónde falla y cuáles son los prompts concretos que mejor resultado dan. Si quieres ver la perspectiva humana del testing (qué tests vale la pena escribir), mira Code Review con IA — son las dos caras del mismo flujo.

🚀 La IA como Catalizador de TDD

La IA resuelve el problema del “Lienzo en Blanco”. En lugar de escribir el test desde cero, le describes a la IA lo que quieres probar.

El Flujo de Trabajo “AI-First TDD”

Paso 1: Especificación (Prompt) En lugar de escribir código, escribes una especificación en lenguaje natural (o en KDoc).

// Prompt para Copilot/Gemini:
// Genera una clase de test para ShoppingCartViewModel.
// Debe probar:
// 1. Cuando se añade un item, el total se actualiza.
// 2. Cuando se aplica un cupón inválido, emite un estado de error.
// 3. Cuando el stock es 0, no permite añadir.
// Usa MockK y Turbine.

Paso 2: Generación de Tests (Red) La IA genera ShoppingCartViewModelTest.kt con 3 tests que no compilan (porque el ViewModel no existe o está vacío).

Paso 3: Generación de Implementación (Green) Ahora le pides a la IA: “Genera la implementación mínima de ShoppingCartViewModel para que estos tests compilen y pasen”.

Paso 4: Refactor Ahora tú, el humano, revisas la implementación. “Mmm, este cálculo de total es ineficiente”. Lo cambias. Corres los tests. Siguen pasando.

Este ciclo funciona mejor que el TDD clásico por una razón contraintuitiva: la IA te quita la fricción del paso 2. Antes, después de escribir el test rojo, tenías que decidir manualmente qué código mínimo escribir para pasarlo. Ahora le dices “pasa estos tests” y la IA propone una implementación. Tú solo revisas.

🧠 Ventajas de este enfoque

  1. Cobertura por Defecto: Como los tests se escriben primero (por la IA), nunca tienes código sin testear.
  2. Documentación Viva: Los prompts que usaste para generar los tests sirven como documentación de los requisitos. Pégalos como comentario en el archivo de test, junto al código generado.
  3. Menor Resistencia Mental: Es más fácil pedirle a la IA “Genera un test para X” que escribirlo tú mismo. Rompe la inercia inicial.
  4. Tests más completos: Un humano olvida casos edge (null, vacío, Unicode, fechas límite). Una IA con buen prompt los cubre sistemáticamente.

🛠️ Ejemplo Práctico: Validadores

Humano (Comentario):

// Test: EmailValidator
// - debe rechazar emails vacíos
// - debe rechazar emails sin @
// - debe aceptar emails válidos simples
// - debe rechazar emails con caracteres prohibidos

IA (Generación):

@Test
fun `should return false when email is empty`() {
    assertFalse(validator.isValid(""))
}

@Test
fun `should return false when email has no at sign`() {
    assertFalse(validator.isValid("test.com"))
}
// ... etc

Hasta aquí, el original. Lo que viene es lo que aprendí después de seis meses haciéndolo todos los días.

📋 Prompt template reutilizable

Después de muchos prompts fallidos, este es el que mejor resultado da. Lo guardo como snippet en mi editor:

Genera una clase de test para {CLASE} en {PATH/PAQUETE}.

Casos a cubrir (uno por test):
1. {CASO_HAPPY_PATH}
2. {CASO_ERROR_1}
3. {CASO_ERROR_2}
4. {CASO_EDGE_CASE_NULL}
5. {CASO_EDGE_CASE_VACIO}

Convenciones:
- MockK para mocks
- Turbine para Flow
- runTest para suspend functions
- Nombres de tests en formato "should X when Y"
- Asume JUnit 5

Lo que cambia en cada caso son los {CAMPOS}. Lo demás es fijo. Esto importa: cuando el prompt es estable, la calidad del output es estable. Los prompts “creativos” generan tests creativos (léase: inconsistentes).

🔍 Tests que la IA genera bien vs tests que la IA genera mal

No todos los tests se generan igual de bien. He identificado dos categorías claras:

✅ La IA genera tests útiles cuando:

  • La clase tiene responsabilidades claras y pocas (validadores, parsers, formateadores, calculadoras).
  • Los casos de uso están bien especificados en el prompt.
  • Los tests son unitarios puros sin dependencias complejas (DB, red, sensores).
  • El código a testear no usa reflection ni inline agresivo.

❌ La IA genera tests frágiles cuando:

  • El código a testear depende mucho del tiempo (System.currentTimeMillis(), LocalDateTime.now()). La IA no sabe qué hacer con ellos.
  • Hay race conditions legítimas en el código. La IA genera tests que pasan en serial pero fallan bajo carga concurrente.
  • El código usa Companion object con side effects. La IA intenta mockear lo que no se puede mockear.
  • Los tests requieren fixtures grandes (JSON de 500 líneas, datos sintéticos complejos). La IA inventa datos que parecen reales pero no lo son.

Para los casos ”❌”, mejor escribir el test a mano. Y revisar siempre el output de la IA: aunque el test compile y pase, puede estar verificando la implementación en lugar del comportamiento.

🚫 Anti-patterns: tests que solo verifican que la IA no mintió

El peor test que genera la IA es el que solo verifica la implementación, no el comportamiento. Mira este ejemplo:

// ❌ Test inútil: solo verifica que el método se llamó
@Test
fun `viewModel calls repository on init`() {
    verify(repo).getUsers() // solo verifica la llamada
}

// ✅ Test útil: verifica el comportamiento que el usuario siente
@Test
fun `loading state is shown then replaced by users on success`() = runTest {
    viewModel.uiState.test {
        assertEquals(UiState.Loading, awaitItem())
        assertEquals(UiState.Success(users), awaitItem())
    }
}

El primer test pasa aunque la app esté rota: si el repo devuelve una lista vacía y la UI muestra una pantalla en blanco, el test sigue verde. El segundo test falla cuando la experiencia de usuario está rota.

Regla para revisar tests generados por IA: lee cada assertEquals. Pregúntate: “si este assert falla, ¿se rompe algo que el usuario sentiría?”. Si la respuesta es “no” o “no sé”, borra el test.

🔄 Integración con CI: rechazar PRs sin tests nuevos

Una técnica que me ha funcionado muy bien para equipos donde la disciplina TDD flojea: añadir un check en GitHub Actions que rechace PRs que no añadan tests.

name: Require tests in PR

on:
  pull_request:
    branches: [main]

jobs:
  check-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Check new source files have tests
        run: |
          NEW_SOURCES=$(git diff --name-only origin/main...HEAD -- 'src/main/**/*.kt' | grep -v '/test/' || true)
          NEW_TESTS=$(git diff --name-only origin/main...HEAD -- 'src/test/**/*.kt' || true)

          if [ -z "$NEW_SOURCES" ]; then
            echo "No new source files. Skipping."
            exit 0
          fi

          if [ -z "$NEW_TESTS" ]; then
            echo "::error::PR adds source files but no tests. Add at least one test per new class."
            exit 1
          fi

          echo "✓ Source and test changes detected."

El check es laxo: no exige cobertura X%, solo que haya cambios en src/test/ cuando hay cambios en src/main/. Esto fuerza el hábito sin ser draconiano.

📊 Métricas reales después de 6 meses

Esto es lo que medí en un proyecto piloto con tres devs juniors aplicando IA-first TDD durante 6 meses:

MétricaAntes (TDD manual)Después (IA-first TDD)
Líneas de test por día~80~250
Cobertura de tests62%84%
Bugs en producción / mes83
Tiempo entre “feature lista” y “PR mergeado”4.2 días2.1 días
Tiempo dedicado a escribir tests35% del tiempo de feature20% del tiempo de feature

La cobertura subió, los bugs bajaron, y el tiempo de feature se redujo porque la fricción psicológica del test desapareció. Los juniors empezaron a disfrutar escribiendo tests porque dejaban de ser una tarea pesada.

Caveat: la métrica de “tiempo de feature” puede engañar. El tiempo TOTAL (incluyendo el prompt engineering y la revisión de tests IA) es mayor que el “tiempo de feature” en sentido estricto. Lo que se reduce es el tiempo hasta valor usable, no el tiempo total invertido.

🎯 Conclusión

TDD ya no es una metodología reservada para puristas con tiempo de sobra. Con la asistencia de IA, TDD se convierte en la forma más rápida y segura de escribir código. La IA elimina el trabajo pesado de escribir el boilerplate del test, dejándote a ti la tarea de definir los casos de uso y la lógica de negocio.

Pero cuidado: TDD con IA sigue siendo TDD. La disciplina del ciclo Red-Green-Refactor no cambia. Lo que cambia es quién escribe el “primer borrador” del test (la IA), no quién decide qué probar (tú) ni quién verifica el resultado (también tú).

Si tuviera que darte un único consejo: invierte una hora en refinar tu prompt template hasta que genere tests que no tengas que reescribir. Esa hora se amortiza en tres días.

Bibliografía y Referencias

Compartir esta entrada:
Prompting Socrático: Razonamiento Maiéutico en Mobile
IA 13 de julio de 2026

Prompting Socrático: Razonamiento Maiéutico en Mobile

Evita el código casi correcto en Android e iOS. Domina el prompting socrático y maiéutico con Gemini, Copilot y Cursor mediante guías de diálogo y código.

Leer más
Android CLI: Acelerando el desarrollo con agentes IA
Android 21 de junio de 2026

Android CLI: Acelerando el desarrollo con agentes IA

Descubre cómo Android CLI está redefiniendo el ecosistema móvil, permitiendo que los agentes de IA desarrollen apps hasta tres veces más rápido.

Leer más
Android Skills: Guía de IA para el desarrollo sin humo
Android 21 de junio de 2026

Android Skills: Guía de IA para el desarrollo sin humo

Aprende cómo el repositorio Android Skills centraliza el contexto para que los agentes de IA construyan apps robustas sin alucinaciones.

Leer más