
Integration Testing
- 492 installs
- 305 repo stars
- Updated March 4, 2026
- aj-geddes/useful-ai-prompts
integration-testing is an agent skill that designs and implements integration tests verifying API endpoints, database operations, and external service interactions for developers who need confidence that components work
About
integration-testing is a Testing & QA skill from aj-geddes/useful-ai-prompts that guides agents through designing and running tests beyond unit isolation. The skill covers component interaction validation, API endpoint testing, database operation checks, and external service communication patterns with reference guides and best practices. Unlike unit tests that mock dependencies, integration tests exercise real boundaries between modules and services. Developers reach for integration-testing when validating REST or GraphQL APIs, ORM database layers, message queues, or third-party SDK calls need end-to-end component verification before a release candidate ships.
- Verifies component interactions across databases, APIs, and external services
- Covers API endpoint testing with real database connections
- Validates service-to-service communication and data flows
- Tests repository/DAO layers, authentication flows, and message queues
- Includes reference guides and best practices for reliable test design
Integration Testing by the numbers
- 492 all-time installs (skills.sh)
- Ranked #618 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill integration-testingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 492 |
|---|---|
| repo stars | ★ 305 |
| Last updated | March 4, 2026 |
| Repository | aj-geddes/useful-ai-prompts ↗ |
How do you write integration tests for APIs and databases?
Design and run integration tests that verify how their API endpoints, databases, and external services interact before shipping.
Who is it for?
Backend developers shipping services with multiple integrated components who need structured guidance for API, database, and external-service test design.
Skip if: Developers who only need isolated unit tests for pure functions without cross-module or network boundaries should use unit-testing skills instead.
When should I use this skill?
A developer asks to write integration tests, validate API endpoints with databases, or test service-layer interactions across components.
What you get
Integration test suites covering API endpoints, database operations, service-layer interactions, and external service mocks or live stubs.
- Integration test suites
- API endpoint test cases
- Database interaction tests
Files
Integration Testing
Table of Contents
Overview
Integration testing validates that different components, modules, or services work correctly together. Unlike unit tests that isolate single functions, integration tests verify the interactions between multiple parts of your system including databases, APIs, external services, and infrastructure.
When to Use
- Testing API endpoints with real database connections
- Verifying service-to-service communication
- Validating data flow across multiple layers
- Testing repository/DAO layer with actual databases
- Checking authentication and authorization flows
- Verifying message queue consumers and producers
- Testing third-party service integrations
Quick Start
Minimal working example:
// test/api/users.integration.test.js
const request = require("supertest");
const app = require("../../src/app");
const { setupTestDB, teardownTestDB } = require("../helpers/db");
describe("User API Integration Tests", () => {
beforeAll(async () => {
await setupTestDB();
});
afterAll(async () => {
await teardownTestDB();
});
beforeEach(async () => {
await clearUsers();
});
describe("POST /api/users", () => {
it("should create a new user with valid data", async () => {
const userData = {
email: "test@example.com",
name: "Test User",
password: "SecurePass123!",
};
// ... (see reference guides for full implementation)Reference Guides
Detailed implementations in the references/ directory:
| Guide | Contents |
|---|---|
| API Integration Testing | API Integration Testing |
| Database Integration Testing | Database Integration Testing |
| External Service Integration | External Service Integration |
| Message Queue Integration | Message Queue Integration |
Best Practices
✅ DO
- Use real databases in integration tests (in-memory or containers)
- Test actual HTTP requests, not mocked responses
- Verify database state after operations
- Test transaction boundaries and rollbacks
- Include authentication/authorization in tests
- Test error scenarios and edge cases
- Use test containers for isolated environments
- Clean up data between tests
❌ DON'T
- Mock database connections in integration tests
- Skip testing error paths
- Leave test data in databases
- Use production databases for testing
- Ignore transaction management
- Test only happy paths
- Share state between tests
- Hardcode URLs or credentials
API Integration Testing
API Integration Testing
Express/Node.js with Jest and Supertest
// test/api/users.integration.test.js
const request = require("supertest");
const app = require("../../src/app");
const { setupTestDB, teardownTestDB } = require("../helpers/db");
describe("User API Integration Tests", () => {
beforeAll(async () => {
await setupTestDB();
});
afterAll(async () => {
await teardownTestDB();
});
beforeEach(async () => {
await clearUsers();
});
describe("POST /api/users", () => {
it("should create a new user with valid data", async () => {
const userData = {
email: "test@example.com",
name: "Test User",
password: "SecurePass123!",
};
const response = await request(app)
.post("/api/users")
.send(userData)
.expect(201);
expect(response.body).toMatchObject({
id: expect.any(String),
email: userData.email,
name: userData.name,
});
expect(response.body.password).toBeUndefined();
// Verify in database
const user = await User.findById(response.body.id);
expect(user).toBeTruthy();
expect(user.email).toBe(userData.email);
});
it("should reject duplicate email addresses", async () => {
const userData = {
email: "test@example.com",
name: "Test",
password: "pass",
};
await request(app).post("/api/users").send(userData).expect(201);
const response = await request(app)
.post("/api/users")
.send(userData)
.expect(409);
expect(response.body.error).toMatch(/email.*exists/i);
});
});
describe("GET /api/users/:id", () => {
it("should retrieve user with associated orders", async () => {
const user = await createTestUser();
await createTestOrder({ userId: user.id, total: 99.99 });
const response = await request(app)
.get(`/api/users/${user.id}`)
.set("Authorization", `Bearer ${user.token}`)
.expect(200);
expect(response.body).toMatchObject({
id: user.id,
orders: expect.arrayContaining([
expect.objectContaining({ total: 99.99 }),
]),
});
});
});
});FastAPI/Python with pytest
# tests/integration/test_user_api.py
import pytest
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession
from app.main import app
from app.models import User
from tests.conftest import test_db
@pytest.mark.asyncio
class TestUserAPI:
async def test_create_user_integration(
self,
client: AsyncClient,
db: AsyncSession
):
"""Test user creation with database persistence."""
user_data = {
"email": "test@example.com",
"name": "Test User",
"password": "SecurePass123!"
}
response = await client.post("/api/users", json=user_data)
assert response.status_code == 201
data = response.json()
assert data["email"] == user_data["email"]
assert "password" not in data
# Verify in database
result = await db.execute(
select(User).where(User.email == user_data["email"])
)
user = result.scalar_one()
assert user is not None
assert user.name == user_data["name"]
async def test_user_with_relationships(
self,
client: AsyncClient,
db: AsyncSession
):
"""Test retrieving user with related data."""
# Setup: Create user with orders
user = await create_test_user(db)
await create_test_order(db, user_id=user.id, total=99.99)
# Test: Fetch user with orders
response = await client.get(
f"/api/users/{user.id}",
headers={"Authorization": f"Bearer {user.token}"}
)
assert response.status_code == 200
data = response.json()
assert data["id"] == user.id
assert len(data["orders"]) == 1
assert data["orders"][0]["total"] == 99.99Database Integration Testing
Database Integration Testing
Spring Boot with JUnit
// src/test/java/com/example/integration/UserRepositoryIntegrationTest.java
@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestPropertySource(locations = "classpath:application-test.properties")
class UserRepositoryIntegrationTest {
@Autowired
private UserRepository userRepository;
@Autowired
private OrderRepository orderRepository;
@Autowired
private TestEntityManager entityManager;
@BeforeEach
void setUp() {
orderRepository.deleteAll();
userRepository.deleteAll();
}
@Test
@Transactional
void testSaveUserWithOrders() {
// Given
User user = new User();
user.setEmail("test@example.com");
user.setName("Test User");
Order order1 = new Order();
order1.setTotal(new BigDecimal("99.99"));
order1.setUser(user);
Order order2 = new Order();
order2.setTotal(new BigDecimal("49.99"));
order2.setUser(user);
user.setOrders(Arrays.asList(order1, order2));
// When
User savedUser = userRepository.save(user);
entityManager.flush();
entityManager.clear();
// Then
User foundUser = userRepository.findById(savedUser.getId())
.orElseThrow();
assertThat(foundUser.getEmail()).isEqualTo("test@example.com");
assertThat(foundUser.getOrders()).hasSize(2);
assertThat(foundUser.getOrders())
.extracting(Order::getTotal)
.containsExactlyInAnyOrder(
new BigDecimal("99.99"),
new BigDecimal("49.99")
);
}
@Test
void testCustomQueryWithJoins() {
// Given
User user = createTestUser("test@example.com");
createTestOrder(user, new BigDecimal("150.00"));
// When
List<User> highValueUsers = userRepository
.findUsersWithOrdersAbove(new BigDecimal("100.00"));
// Then
assertThat(highValueUsers).hasSize(1);
assertThat(highValueUsers.get(0).getEmail())
.isEqualTo("test@example.com");
}
}External Service Integration
External Service Integration
Testing with Test Containers
// test/integration/payment-service.test.js
const { GenericContainer } = require("testcontainers");
const PaymentService = require("../../src/services/payment");
describe("Payment Service Integration", () => {
let container;
let paymentService;
beforeAll(async () => {
// Start PostgreSQL container
container = await new GenericContainer("postgres:14")
.withEnvironment({
POSTGRES_DB: "test",
POSTGRES_USER: "test",
POSTGRES_PASSWORD: "test",
})
.withExposedPorts(5432)
.start();
const connectionString = `postgresql://test:test@${container.getHost()}:${container.getMappedPort(5432)}/test`;
paymentService = new PaymentService(connectionString);
await paymentService.initialize();
}, 60000);
afterAll(async () => {
await paymentService.close();
await container.stop();
});
test("should process payment and update database", async () => {
const payment = {
orderId: "order-123",
amount: 99.99,
currency: "USD",
paymentMethod: "credit_card",
};
const result = await paymentService.processPayment(payment);
expect(result.status).toBe("completed");
expect(result.transactionId).toBeDefined();
// Verify in database
const stored = await paymentService.getPayment(result.id);
expect(stored.orderId).toBe("order-123");
expect(stored.status).toBe("completed");
});
});Message Queue Integration
Message Queue Integration
# tests/integration/test_message_queue.py
import pytest
from unittest.mock import patch
import json
from app.queue import MessageQueue
from app.workers import OrderProcessor
@pytest.mark.integration
class TestMessageQueueIntegration:
@pytest.fixture
async def queue(self):
"""Create test message queue."""
queue = MessageQueue(url=TEST_RABBITMQ_URL)
await queue.connect()
yield queue
await queue.close()
async def test_publish_and_consume_message(self, queue):
"""Test full message lifecycle."""
received_messages = []
async def message_handler(message):
received_messages.append(message)
# Subscribe to queue
await queue.subscribe('orders', message_handler)
# Publish message
order_data = {
'order_id': '123',
'customer': 'test@example.com',
'total': 99.99
}
await queue.publish('orders', order_data)
# Wait for message processing
await asyncio.sleep(0.5)
assert len(received_messages) == 1
assert received_messages[0]['order_id'] == '123'
async def test_order_processing_workflow(self, queue, db):
"""Test complete order processing through queue."""
processor = OrderProcessor(queue, db)
await processor.start()
# Publish order
order = await create_test_order(db, status='pending')
await queue.publish('orders.new', {'order_id': order.id})
# Wait for processing
await asyncio.sleep(1)
# Verify order was processed
await db.refresh(order)
assert order.status == 'processing'
assert order.processed_at is not None#!/bin/bash
# scaffold-tests.sh - Generate test file scaffolding
# Usage: ./scaffold-tests.sh <source_file> [--framework jest|pytest|mocha]
set -euo pipefail
SOURCE_FILE="${{1:?Usage: $0 <source_file> [--framework jest|pytest|mocha]}}"
FRAMEWORK="${{2:-jest}}"
echo "Scaffolding tests for: $SOURCE_FILE (framework: $FRAMEWORK)"
# TODO: Implement test scaffolding logic
# - Parse source file for exported functions/classes
# - Generate test stubs for each export
# - Include setup/teardown boilerplate
# - Add common assertion patterns
echo "Test scaffolding complete."
// Test Template
// TODO: Customize for your testing framework and project
describe('ModuleName', () => {
// Setup
beforeEach(() => {
// TODO: Add test setup
});
afterEach(() => {
// TODO: Add cleanup
});
describe('functionName', () => {
it('should handle the happy path', () => {
// TODO: Add assertion
});
it('should handle edge cases', () => {
// TODO: Add edge case tests
});
it('should handle errors gracefully', () => {
// TODO: Add error handling tests
});
});
});
Related skills
How it compares
Pick integration-testing when multiple components must be exercised together; use unit-testing skills when isolating individual functions suffices.
FAQ
What does integration-testing cover beyond unit tests?
integration-testing validates that components, modules, and services work together—API endpoints, database operations, and external service communication. Unlike unit tests that isolate single functions, integration tests verify real cross-boundary interactions.
When should developers use the integration-testing skill?
Developers should use integration-testing when designing integration test suites, API tests, end-to-end component tests, or service layer validation. The skill provides quick start guides, reference material, and best practices for pre-ship verification.