Claude
Skills
Sign in
Back

backend-testing

Included with Lifetime
$97 forever

Write comprehensive backend tests including unit tests, integration tests, and API tests. Use when testing REST APIs, database operations, authentication flows, or business logic. Handles Jest, Pytest, Mocha, testing strategies, mocking, and test coverage.

Backend & APIs

What this skill does



# Backend Testing


## When to use this skill

Specific situations that should trigger this skill:

- **New feature development**: Write tests first using TDD (Test-Driven Development)
- **Adding API endpoints**: Test success and failure cases for REST APIs
- **Bug fixes**: Add tests to prevent regressions
- **Before refactoring**: Write tests that guarantee existing behavior
- **CI/CD setup**: Build automated test pipelines

## Input Format

Format and required/optional information to collect from the user:

### Required information
- **Framework**: Express, Django, FastAPI, Spring Boot, etc.
- **Test tool**: Jest, Pytest, Mocha/Chai, JUnit, etc.
- **Test target**: API endpoints, business logic, DB operations, etc.

### Optional information
- **Database**: PostgreSQL, MySQL, MongoDB (default: in-memory DB)
- **Mocking library**: jest.mock, sinon, unittest.mock (default: framework built-in)
- **Coverage target**: 80%, 90%, etc. (default: 80%)
- **E2E tool**: Supertest, TestClient, RestAssured (optional)

### Input example

```
Test the user authentication endpoints for an Express.js API:
- Framework: Express + TypeScript
- Test tool: Jest + Supertest
- Target: POST /auth/register, POST /auth/login
- DB: PostgreSQL (in-memory for tests)
- Coverage: 90% or above
```

## Instructions

Step-by-step task order to follow precisely.

### Step 1: Set up the test environment

Install and configure the test framework and tools.

**Tasks**:
- Install test libraries
- Configure test database (in-memory or separate DB)
- Separate environment variables (.env.test)
- Configure jest.config.js or pytest.ini

**Example** (Node.js + Jest + Supertest):
```bash
npm install --save-dev jest ts-jest @types/jest supertest @types/supertest
```

**jest.config.js**:
```javascript
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/src'],
  testMatch: ['**/__tests__/**/*.test.ts'],
  collectCoverageFrom: [
    'src/**/*.ts',
    '!src/**/*.d.ts',
    '!src/__tests__/**'
  ],
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80
    }
  },
  setupFilesAfterEnv: ['<rootDir>/src/__tests__/setup.ts']
};
```

**setup.ts** (global test configuration):
```typescript
import { db } from '../database';

// Reset DB before each test
beforeEach(async () => {
  await db.migrate.latest();
  await db.seed.run();
});

// Clean up after each test
afterEach(async () => {
  await db.migrate.rollback();
});

// Close connection after all tests complete
afterAll(async () => {
  await db.destroy();
});
```

### Step 2: Write Unit Tests (business logic)

Write unit tests for individual functions and classes.

**Tasks**:
- Test pure functions (no dependencies)
- Isolate dependencies via mocking
- Test edge cases (boundary values, exceptions)
- AAA pattern (Arrange-Act-Assert)

**Decision criteria**:
- No external dependencies (DB, API) -> pure Unit Test
- External dependencies present -> use Mock/Stub
- Complex logic -> test various input cases

**Example** (password validation function):
```typescript
// src/utils/password.ts
export function validatePassword(password: string): { valid: boolean; errors: string[] } {
  const errors: string[] = [];

  if (password.length < 8) {
    errors.push('Password must be at least 8 characters');
  }

  if (!/[A-Z]/.test(password)) {
    errors.push('Password must contain uppercase letter');
  }

  if (!/[a-z]/.test(password)) {
    errors.push('Password must contain lowercase letter');
  }

  if (!/\d/.test(password)) {
    errors.push('Password must contain number');
  }

  if (!/[!@#$%^&*]/.test(password)) {
    errors.push('Password must contain special character');
  }

  return { valid: errors.length === 0, errors };
}

// src/__tests__/utils/password.test.ts
import { validatePassword } from '../../utils/password';

describe('validatePassword', () => {
  it('should accept valid password', () => {
    const result = validatePassword('Password123!');
    expect(result.valid).toBe(true);
    expect(result.errors).toHaveLength(0);
  });

  it('should reject password shorter than 8 characters', () => {
    const result = validatePassword('Pass1!');
    expect(result.valid).toBe(false);
    expect(result.errors).toContain('Password must be at least 8 characters');
  });

  it('should reject password without uppercase', () => {
    const result = validatePassword('password123!');
    expect(result.valid).toBe(false);
    expect(result.errors).toContain('Password must contain uppercase letter');
  });

  it('should reject password without lowercase', () => {
    const result = validatePassword('PASSWORD123!');
    expect(result.valid).toBe(false);
    expect(result.errors).toContain('Password must contain lowercase letter');
  });

  it('should reject password without number', () => {
    const result = validatePassword('Password!');
    expect(result.valid).toBe(false);
    expect(result.errors).toContain('Password must contain number');
  });

  it('should reject password without special character', () => {
    const result = validatePassword('Password123');
    expect(result.valid).toBe(false);
    expect(result.errors).toContain('Password must contain special character');
  });

  it('should return multiple errors for invalid password', () => {
    const result = validatePassword('pass');
    expect(result.valid).toBe(false);
    expect(result.errors.length).toBeGreaterThan(1);
  });
});
```

### Step 3: Integration Test (API endpoints)

Write integration tests for API endpoints.

**Tasks**:
- Test HTTP requests/responses
- Success cases (200, 201)
- Failure cases (400, 401, 404, 500)
- Authentication/authorization tests
- Input validation tests

**Checklist**:
- [x] Verify status code
- [x] Validate response body structure
- [x] Confirm database state changes
- [x] Validate error messages

**Example** (Express.js + Supertest):
```typescript
// src/__tests__/api/auth.test.ts
import request from 'supertest';
import app from '../../app';
import { db } from '../../database';

describe('POST /auth/register', () => {
  it('should register new user successfully', async () => {
    const response = await request(app)
      .post('/api/auth/register')
      .send({
        email: '[email protected]',
        username: 'testuser',
        password: 'Password123!'
      });

    expect(response.status).toBe(201);
    expect(response.body).toHaveProperty('user');
    expect(response.body).toHaveProperty('accessToken');
    expect(response.body.user.email).toBe('[email protected]');

    // Verify the record was actually saved to DB
    const user = await db.user.findUnique({ where: { email: '[email protected]' } });
    expect(user).toBeTruthy();
    expect(user.username).toBe('testuser');
  });

  it('should reject duplicate email', async () => {
    // Create first user
    await request(app)
      .post('/api/auth/register')
      .send({
        email: '[email protected]',
        username: 'user1',
        password: 'Password123!'
      });

    // Second attempt with same email
    const response = await request(app)
      .post('/api/auth/register')
      .send({
        email: '[email protected]',
        username: 'user2',
        password: 'Password123!'
      });

    expect(response.status).toBe(409);
    expect(response.body.error).toContain('already exists');
  });

  it('should reject weak password', async () => {
    const response = await request(app)
      .post('/api/auth/register')
      .send({
        email: '[email protected]',
        username: 'testuser',
        password: 'weak'
      });

    expect(response.status).toBe(400);
    expect(response.body.error).toBeDefined();
  });

  it('should reject missing fields', async () => {
    const response = await request(app)
      .post('/api/auth/register')
      .send({
        email: '[email protected]'
        // username, password omitted
      });

    expect(response.status).toBe(400);
  });
});

descri

Related in Backend & APIs