Los servidores mock son herramientas esenciales para el desarrollo móvil, permitiendo a los equipos desarrollar y probar aplicaciones antes de que las APIs backend estén listas, simular casos extremos y trabajar offline. Combinados con estrategias apropiadas de testing de APIs, los servidores mock forman la base de los flujos de trabajo modernos de desarrollo móvil. Esta guía cubre las soluciones de mock server más populares y su implementación práctica.

Por Qué Importan los Mock Servers para Desarrollo Móvil

Beneficios Clave

  1. Desarrollo Paralelo: Equipos frontend y backend trabajan independientemente
  2. Testing Offline: Desarrollar sin conectividad a internet
  3. Simulación de Casos Extremos: Probar escenarios de error, rate limiting, timeouts
  4. Datos de Prueba Consistentes: Entornos de prueba reproducibles
  5. Integración CI/CD: Tests automatizados rápidos y confiables
  6. Reducción de Costos: Sin infraestructura backend necesaria para desarrollo local

Escenario Real

Sin Mock Server:
- API backend retrasada 3 semanas
- Equipo móvil bloqueado
- Problemas de integración descubiertos tarde
- Testing depende de entorno staging compartido

Con Mock Server:
- Equipo móvil empieza inmediatamente
- Contrato definido por adelantado
- Casos extremos probados temprano
- Pipelines CI paralelos
- Problemas de integración detectados durante desarrollo

Soluciones Populares de Mock Server

Tabla Comparativa

CaracterísticaWireMockMockoonjson-serverMSW
Complejidad SetupMediaBajaMuy BajaBaja
ConfiguraciónJava/JSONGUI/JSONJSONJavaScript
Coincidencia RequestAvanzadaBuenaBásicaAvanzada
Templating RespuestaHandlebarsHandlebarsEstáticaDinámica
Modo ProxyNo
Record & ReplayNoNo
Integración CIExcelenteBuenaExcelenteExcelente
Mejor ParaAPIs complejasSetup rápidoPrototipadoApps basadas en navegador

WireMock: La Solución Empresarial

Instalación y Configuración

Docker (recomendado para CI/CD móvil):

# Ejecutar contenedor WireMock
docker run -d \
  --name wiremock \
  -p 8080:8080 \
  -v $(pwd)/wiremock:/home/wiremock \
  wiremock/wiremock:latest

JAR Standalone:

# Descargar WireMock
wget https://repo1.maven.org/maven2/org/wiremock/wiremock-standalone/3.3.1/wiremock-standalone-3.3.1.jar

# Ejecutar WireMock
java -jar wiremock-standalone-3.3.1.jar --port 8080

Ejemplos de Configuración

Stub Básico (wiremock/mappings/get-user.json):

{
  "request": {
    "method": "GET",
    "urlPathPattern": "/api/users/([0-9]+)"
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "jsonBody": {
      "id": "{{request.pathSegments.[2]}}",
      "username": "juan_perez",
      "email": "juan@ejemplo.com",
      "avatar": "https://cdn.ejemplo.com/avatar.jpg",
      "createdAt": "2024-01-15T10:30:00Z"
    },
    "transformers": ["response-template"]
  }
}

Templating Avanzado de Respuesta:

{
  "request": {
    "method": "POST",
    "url": "/api/orders",
    "headers": {
      "Content-Type": {
        "equalTo": "application/json"
      }
    }
  },
  "response": {
    "status": 201,
    "headers": {
      "Content-Type": "application/json",
      "Location": "/api/orders/{{randomValue type='UUID'}}"
    },
    "jsonBody": {
      "orderId": "{{randomValue type='UUID'}}",
      "status": "pendiente",
      "createdAt": "{{now format='yyyy-MM-dd HH:mm:ss'}}",
      "items": "{{jsonPath request.body '$.items'}}",
      "total": "{{jsonPath request.body '$.total'}}"
    },
    "transformers": ["response-template"]
  }
}

Simulación de Errores:

{
  "scenarioName": "Rate Limiting",
  "requiredScenarioState": "Started",
  "newScenarioState": "Rate Limited",
  "request": {
    "method": "GET",
    "url": "/api/products"
  },
  "response": {
    "status": 429,
    "headers": {
      "Content-Type": "application/json",
      "Retry-After": "60"
    },
    "jsonBody": {
      "error": "rate_limit_exceeded",
      "message": "Demasiadas peticiones. Intente de nuevo más tarde.",
      "retryAfter": 60
    }
  }
}

Simulación de Latencia de Red:

{
  "request": {
    "method": "GET",
    "url": "/api/slow-endpoint"
  },
  "response": {
    "status": 200,
    "fixedDelayMilliseconds": 3000,
    "jsonBody": {
      "message": "Esta respuesta fue retrasada 3 segundos"
    }
  }
}

Integración Android

// app/build.gradle.kts
dependencies {
    // WireMock para tests instrumentados
    androidTestImplementation("com.github.tomakehurst:wiremock-jre8:2.35.0")
}

// Setup AndroidTest
class WireMockTest {
    private lateinit var wireMockServer: WireMockServer

    @Before
    fun setup() {
        wireMockServer = WireMockServer(
            WireMockConfiguration.options()
                .port(8080)
                .notifier(ConsoleNotifier(true))
        )
        wireMockServer.start()
        WireMock.configureFor("localhost", 8080)
    }

    @After
    fun tearDown() {
        wireMockServer.stop()
    }

    @Test
    fun testUserFetch() {
        // Configurar stub
        stubFor(
            get(urlEqualTo("/api/users/123"))
                .willReturn(
                    aResponse()
                        .withStatus(200)
                        .withHeader("Content-Type", "application/json")
                        .withBody("""
                            {
                              "id": 123,
                              "username": "usuario_prueba",
                              "email": "prueba@ejemplo.com"
                            }
                        """.trimIndent())
                )
        )

        // Configurar app para usar URL de WireMock
        val apiClient = ApiClient("http://localhost:8080")

        // Ejecutar test
        runBlocking {
            val user = apiClient.getUser(123)
            assertEquals("usuario_prueba", user.username)
        }

        // Verificar que se hizo la petición
        verify(
            getRequestedFor(urlEqualTo("/api/users/123"))
                .withHeader("Accept", equalTo("application/json"))
        )
    }
}

Mockoon: Enfoque GUI-First

Instalación

# macOS
brew install --cask mockoon

# O descargar desde https://mockoon.com

Configuración

Crear API Mock (vía GUI):

  1. Abrir Mockoon
  2. Crear nuevo entorno: “Mobile API Mock”
  3. Configurar puerto: 3000
  4. Añadir rutas:
    • GET /api/users → Respuesta con array de usuarios
    • POST /api/auth/login → Retornar token JWT
    • GET /api/products → Productos paginados

Configuración Programática (mockoon-data.json):

{
  "uuid": "mobile-api-mock",
  "name": "Mobile API Mock",
  "port": 3000,
  "routes": [
    {
      "uuid": "route-1",
      "method": "get",
      "endpoint": "api/users/:id",
      "responses": [
        {
          "uuid": "response-1",
          "body": "{\n  \"id\": \"{{urlParam 'id'}}\",\n  \"username\": \"{{faker 'internet.userName'}}\",\n  \"email\": \"{{faker 'internet.email'}}\",\n  \"avatar\": \"{{faker 'image.avatar'}}\"\n}",
          "statusCode": 200,
          "headers": [
            {
              "key": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      ]
    },
    {
      "uuid": "route-2",
      "method": "post",
      "endpoint": "api/auth/login",
      "responses": [
        {
          "uuid": "response-2",
          "body": "{\n  \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.{{faker 'random.alphaNumeric' 50}}\",\n  \"expiresIn\": 3600,\n  \"user\": {\n    \"id\": \"{{faker 'random.uuid'}}\",\n    \"email\": \"{{body 'email'}}\"\n  }\n}",
          "statusCode": 200
        }
      ]
    }
  ]
}

Uso CLI (para CI/CD):

# Instalar Mockoon CLI
npm install -g @mockoon/cli

# Ejecutar mock server
mockoon-cli start --data ./mockoon-data.json --port 3000

# Ejecutar en background
mockoon-cli start --data ./mockoon-data.json --daemon-name mobile-mock

json-server: Prototipado Rápido

Instalación y Configuración

# Instalar globalmente
npm install -g json-server

# O como dependencia dev
npm install --save-dev json-server

Crear Base de Datos Mock (db.json):

{
  "users": [
    {
      "id": 1,
      "username": "juan_perez",
      "email": "juan@ejemplo.com",
      "role": "admin"
    },
    {
      "id": 2,
      "username": "maria_garcia",
      "email": "maria@ejemplo.com",
      "role": "user"
    }
  ],
  "posts": [
    {
      "id": 1,
      "userId": 1,
      "title": "Primer Post",
      "content": "¡Hola mundo!",
      "createdAt": "2024-01-15T10:00:00Z"
    }
  ],
  "comments": [
    {
      "id": 1,
      "postId": 1,
      "userId": 2,
      "text": "¡Gran post!",
      "createdAt": "2024-01-15T11:00:00Z"
    }
  ]
}

Rutas Personalizadas (routes.json):

{
  "/api/*": "/$1",
  "/api/users/:id/posts": "/posts?userId=:id",
  "/api/posts/:id/comments": "/comments?postId=:id"
}

Ejecutar Servidor:

# Básico
json-server --watch db.json --port 3000

# Con rutas personalizadas
json-server --watch db.json --routes routes.json --port 3000

# Con simulación de delay
json-server --watch db.json --delay 1000

Integración CI/CD

La integración de servidores mock en pipelines CI/CD permite testing automatizado rápido y confiable. Para frameworks de testing de APIs basados en Java como REST Assured, WireMock proporciona integración perfecta con configuración mínima. Las pruebas móviles modernas en iOS y Android dependen cada vez más de estas integraciones.

GitHub Actions con WireMock

# .github/workflows/mobile-tests.yml
name: Mobile Tests

on: [push, pull_request]

jobs:
  android-tests:
    runs-on: ubuntu-latest

    services:
      wiremock:
        image: wiremock/wiremock:latest
        ports:
          - 8080:8080
        volumes:
          - ${{ github.workspace }}/wiremock:/home/wiremock

    steps:
      - uses: actions/checkout@v3

      - name: Configurar WireMock stubs
        run: |
          cp -r test-fixtures/wiremock/* wiremock/

      - name: Configurar JDK
        uses: actions/setup-java@v3
        with:
          distribution: 'temurin'
          java-version: '17'

      - name: Ejecutar Tests Android
        run: |
          ./gradlew connectedAndroidTest \
            -Dapi.base.url=http://localhost:8080

Mejores Prácticas

1. Desarrollo Contract-First

Define contratos API (OpenAPI/Swagger) antes de implementación. Genera stubs mock desde contratos. Este enfoque se alinea perfectamente con testing de contratos API para aplicaciones móviles, asegurando que los equipos frontend y backend permanezcan sincronizados.

2. Control de Versiones para Configs Mock

project/
├── wiremock/
│   ├── mappings/
│   │   ├── users.json
│   │   └── products.json
│   └── __files/
│       └── large-response.json
└── .gitignore (excluir __files para archivos grandes)

3. Configuraciones Específicas por Entorno

// Android BuildConfig
android {
    buildTypes {
        debug {
            buildConfigField("String", "API_BASE_URL", "\"http://localhost:8080\"")
        }
        release {
            buildConfigField("String", "API_BASE_URL", "\"https://api.production.com\"")
        }
    }
}

4. Datos Realistas con Faker

Usa integración Faker.js de Mockoon o templating de respuesta WireMock:

{
  "username": "{{faker 'internet.userName'}}",
  "avatar": "{{faker 'image.avatar'}}",
  "createdAt": "{{faker 'date.past'}}"
}

Conclusión

Los mock servers son indispensables para el desarrollo móvil moderno:

  • WireMock: Mejor para APIs empresariales complejas, CI/CD, testing de contratos
  • Mockoon: Ideal para setup rápido, flujo basado en GUI, colaboración en equipo
  • json-server: Perfecto para prototipado, APIs CRUD simples, demos rápidas

Elige según las necesidades de tu equipo, infraestructura existente y requisitos de complejidad. Combina múltiples soluciones cuando sea apropiado—usa json-server para prototipado, luego migra a WireMock para testing de grado producción.

Próximos Pasos:

  1. Configura un mock server para tu proyecto actual
  2. Integra con pipeline CI/CD
  3. Crea configuraciones mock reutilizables
  4. Establece flujo de testing de contratos API