Skip to content
cccskills
FreePublished on GitHub

unit-testing-patterns

Unit testing patterns for backend and frontend. AAA structure, effective mocking, test isolation.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md3.4 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

The AAA Pattern

Every test follows Arrange-Act-Assert:

it('creates a user with hashed password', async () => {
  // ARRANGE — set up inputs and mocks
  const dto = { email: 'test@example.com', password: 'plaintext' };
  const mockRepo = { save: vi.fn().mockResolvedValue({ id: '1', ...dto }) };
  const service = new UserService(mockRepo);

  // ACT — call the thing under test
  const user = await service.createUser(dto);

  // ASSERT — verify the outcome
  expect(user.id).toBe('1');
  expect(mockRepo.save).toHaveBeenCalledWith(
    expect.objectContaining({ email: dto.email })
  );
  expect(mockRepo.save.mock.calls[0][0].password).not.toBe('plaintext');
});

What to Mock

Mock: External I/O — database, network, filesystem, timers, random values

Don't mock: Pure functions, your own business logic, constants

// GOOD: mock the database (I/O)
vi.mock('./db', () => ({ findUser: vi.fn() }));

// BAD: mock your own service (you'd be testing the mock, not the code)
vi.mock('./userService');

Mocking Strategies

Spies (observe without replacing)

const logSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
// ... do something
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Error'));
logSpy.mockRestore();

Stubs (replace with controlled value)

const getTimeSpy = vi.spyOn(Date, 'now').mockReturnValue(1234567890);

Module mocks

vi.mock('./email-service', () => ({
  sendEmail: vi.fn().mockResolvedValue({ success: true }),
}));

Test Isolation

describe('UserService', () => {
  let service: UserService;
  let mockRepo: ReturnType<typeof createMockRepo>;

  beforeEach(() => {
    // Fresh instance per test — no shared state
    mockRepo = createMockRepo();
    service = new UserService(mockRepo);
  });

  afterEach(() => {
    vi.clearAllMocks();
  });
});

Assertion Best Practices

// Be specific — assert exact values when meaningful
expect(result.count).toBe(3); // not toBeTruthy()

// Use asymmetric matchers for dynamic values
expect(result).toEqual(expect.objectContaining({
  id: expect.any(String),
  createdAt: expect.any(Date),
  name: 'Alice',
}));

// Test error type specifically
await expect(service.delete('nonexistent')).rejects.toThrow(NotFoundError);

// Don't over-assert (don't test internals)
// BAD: testing private method was called
// GOOD: testing the public observable outcome

Test Naming

// Format: [unit] [scenario] [expected result]
it('returns null when user is not found')
it('throws UnauthorizedError when password is wrong')
it('sends welcome email after registration')
it('does not send email when dry-run mode is enabled')

File Organization

src/
  users/
    users.service.ts
    users.service.test.ts     ← co-located
    users.repository.ts
    users.repository.test.ts  ← co-located

Coverage Thresholds

Minimum per module: 80% Critical paths (auth, payments): 95%

// vitest.config.ts
coverage: {
  thresholds: { lines: 80, functions: 80, branches: 75 }
}

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

anoa

Free

Drive a real browser from the command line — open pages, snapshot the interactive elements as refs, click and fill by ref, read text, run JS, screenshot. Use when a task needs a live browser: checking a page renders, walking a login or checkout flow, scraping something that only exists after JavaScript runs, or reproducing a UI bug.

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

Run linters/typecheckers to calculate health score.

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

Comprehensive UI/UX compliance check (A11y, performance, responsive).

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

Infrastructure-first security audit (OWASP, secrets, dependencies).

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

auth

Free

Setup authentication flow (register, login, session/JWT, middleware)

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

Deep knowledge about deploying applications to AWS (EC2, ECS, S3, CloudFront, Cloud Run).

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

See all skills by porcupine-md

Report a problem with this skill