Mock APIs in GitHub Actions — Reliable CI/CD Without Flaky Dependencies
Flaky CI tests waste hours every sprint. Most failures trace back to one root cause: network calls to real APIs that are slow, rate-limited, or temporarily unavailable. Mock APIs in GitHub Actions give you deterministic, fast test runs every time.
This guide shows you how to wire hosted mock endpoints into your GitHub Actions workflows so integration tests always run against predictable data with controlled response codes.
Why CI Tests Fail
The pattern is always the same. Tests pass locally, fail in CI, and the team spends 20 minutes rerunning the pipeline before someone finds it was a transient network issue. Common causes:
- Third-party APIs hit rate limits during concurrent test runs.
- Staging environments go down during deployments.
- DNS resolution or TLS handshake adds unpredictable latency.
- Test data is mutated by other pipelines sharing the same environment.
Mock APIs fix all of these by removing the external dependency entirely.
Architecture: Mock API + GitHub Actions
The approach is straightforward:
- Create mock endpoints that match your API contract (OpenAPI, GraphQL, or manual routes).
- Store the mock base URL as a GitHub Actions secret or environment variable.
- Point your test suite at the mock URL instead of staging.
- Run tests — every call hits a deterministic endpoint with known payloads.
Step 1: Set Up Mock Endpoints
In moqapi.dev, create a project and import your OpenAPI spec. Every route becomes a live endpoint instantly. For example, if your spec defines GET /users and POST /orders, both are available immediately with AI-generated response data.
You can also configure specific error responses for routes you want to test failure paths on — 401 for expired tokens, 429 for rate limiting, 500 for server errors.
Step 2: Configure GitHub Actions Workflow
# .github/workflows/ci.yml
name: CI Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
API_BASE_URL: https://moqapi.dev/api/invoke/mock/YOUR_API_ID
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Run integration tests
run: npm test
env:
API_BASE_URL: ${{ env.API_BASE_URL }}
The API_BASE_URL environment variable points every test request at the mock endpoint. No code changes needed — your app already reads from this variable.
Step 3: Write Tests Against Mock Endpoints
// tests/users.test.ts
const API_BASE = process.env.API_BASE_URL || 'http://localhost:3000';
describe('Users API', () => {
it('returns a list of users', async () => {
const res = await fetch(API_BASE + '/users');
expect(res.status).toBe(200);
const users = await res.json();
expect(Array.isArray(users)).toBe(true);
expect(users.length).toBeGreaterThan(0);
expect(users[0]).toHaveProperty('id');
expect(users[0]).toHaveProperty('email');
});
it('handles 404 for missing user', async () => {
const res = await fetch(API_BASE + '/users/nonexistent-id');
expect(res.status).toBe(404);
});
});
Step 4: Test Error Paths
Configure mock routes to return specific error codes. In moqapi.dev, you can set up chaos rules per endpoint:
- 401 Unauthorized: test token refresh flows.
- 429 Too Many Requests: test retry logic and backoff.
- 500 Internal Server Error: test graceful degradation.
- Timeout (10s delay): test request timeout handling.
# Test error handling separately
curl -X GET "$API_BASE_URL/users?forceStatus=429"
curl -X GET "$API_BASE_URL/users?forceStatus=500"
Parallel Test Jobs with Isolated Mocks
If you run multiple test suites in parallel, each job can use the same mock project. Mock endpoints are stateless by default, so parallel reads do not conflict. For stateful tests (POST/PUT/DELETE), create separate mock projects per job or use moqapi.dev's environment isolation.
jobs:
test-api:
runs-on: ubuntu-latest
env:
API_BASE_URL: https://moqapi.dev/api/invoke/mock/API_ID_1
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:api
test-auth:
runs-on: ubuntu-latest
env:
API_BASE_URL: https://moqapi.dev/api/invoke/mock/API_ID_2
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:auth
Contract Drift Detection in CI
Add a step that compares your current OpenAPI spec against the mock project's last imported version. moqapi.dev flags breaking changes — removed fields, changed types, deleted endpoints — so you catch contract drift before it hits production.
# Add as a CI step
- name: Check for contract drift
run: |
curl -s "https://moqapi.dev/api/drift/check/YOUR_API_ID" \
-H "Authorization: Bearer ${{ secrets.MOQAPI_TOKEN }}" \
| jq '.breaking_changes'
Environment Matrix Strategy
Use GitHub Actions matrix builds to test against multiple mock configurations:
strategy:
matrix:
scenario: [happy-path, error-handling, rate-limited]
include:
- scenario: happy-path
api_url: https://moqapi.dev/api/invoke/mock/HAPPY_PATH_ID
- scenario: error-handling
api_url: https://moqapi.dev/api/invoke/mock/ERROR_PATH_ID
- scenario: rate-limited
api_url: https://moqapi.dev/api/invoke/mock/RATE_LIMITED_ID
Each matrix entry tests a different failure scenario with the same test code.
What Success Looks Like
- CI pipelines finish in under 3 minutes instead of 8+.
- Flaky test reruns drop to near zero.
- New team members can run full integration tests on day one.
- Error handling is tested continuously, not just before releases.
Common Mistakes to Avoid
- Hardcoding URLs in test files. Always use environment variables so switching between mock and real APIs is a config change.
- Skipping error path tests. If you only test happy paths, production failures will surprise you.
- Using shared mutable state across parallel jobs. Use separate mock projects or stateless endpoints for parallel test runs.
- Not versioning mock configs. Treat your mock API setup as code — version it alongside your test suite.
Migrating from Staging Dependencies
If your CI currently hits a staging API, the migration is a single environment variable change. Update API_BASE_URL in your workflow file and ensure your mock routes match the staging contract. Run both in parallel for a sprint if you want to validate parity.
Final Takeaway
Mock APIs in GitHub Actions eliminate the #1 source of CI flakiness: unreliable external dependencies. One environment variable, one hosted mock project, and your test pipeline becomes deterministic, fast, and trustworthy.
Set up your first CI mock project at moqapi.dev/signup.
About the Author
Founder and sole developer of moqapi.dev. Full-stack engineer with deep experience in API platforms, serverless runtimes, and developer tooling. Built moqapi to solve the mock data and deployment friction she experienced firsthand building production APIs.
Related Articles
What Is Mock Data and Why It Matters for Modern Development
Understand mock data, its role in frontend and backend testing, and how moqapi.dev automates the creation of realistic test payloads for every API endpoint.
API Testing Strategies for Modern Engineering Teams
Contract tests, snapshot tests, fuzz testing — explore the testing matrix every team needs, with examples using Node.js, Python, and moqapi.dev.
Free OpenAPI Mock Server: Generate Realistic API Responses Without Writing Code
Skip boilerplate and JSON fixtures. Learn how to spin up a fully functional OpenAPI mock server for free with auto-generated, schema-accurate response data.
Ready to build?
Start deploying serverless functions in under a minute.