Claude Code Plugins

Community-maintained marketplace

Feedback

Unit Test Writing

@boetro/dotclaude
0
0

This skill should be used when the user asks to "write tests", "add unit tests", "create test cases", "test this function", "add test coverage", or discusses testing strategies and test implementation.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name Unit Test Writing
description This skill should be used when the user asks to "write tests", "add unit tests", "create test cases", "test this function", "add test coverage", or discusses testing strategies and test implementation.

Unit Test Writing Guidelines

When writing unit tests, follow these core principles and guidelines.

Core Principles

1. No Duplicate Testing

Each test should verify a unique behavior. Avoid redundant test cases that exercise the same code path.

Bad: Testing a function that processes a list with separate tests for 1 element, 2 elements, and n elements when they all follow the same logic.

Good: Test the meaningful edge cases only - empty list, single element (if there's special handling), and a representative case for multiple elements.

2. Mock External Packages Only

Use mocks for external dependencies from outside the module. Do NOT mock:

  • Core/standard library modules (typing, collections, etc.)
  • Data classes and models (pydantic, dataclasses, attrs, TypedDict)
  • Pure utility functions within the same package

Mock these:

  • External API clients (requests, httpx, boto3)
  • Database connections and ORMs
  • File system operations (when testing logic, not I/O)
  • Third-party service integrations
  • Time/datetime for deterministic tests

3. Never Mock Private Methods

Private methods (_method in Python, #method in JS) should be exercised through their public interface, not mocked. If you need to mock a private method, it's a sign the code should be refactored.

Test File Location

Place test files alongside source files:

src/
  user_service.py
  test_user_service.py
  utils/
    helpers.py
    test_helpers.py

Language-Specific Guidelines

Python (pytest)

Use pytest unless the project already uses unittest.

import pytest
from unittest.mock import Mock, patch, MagicMock

# Fixture for reusable setup
@pytest.fixture
def user_service(mock_db):
    return UserService(db=mock_db)

# Mock external dependency
@pytest.fixture
def mock_db():
    return Mock(spec=DatabaseClient)

# Test naming: test_<method>_<scenario>_<expected>
def test_create_user_valid_input_returns_user(user_service, mock_db):
    # Arrange
    mock_db.insert.return_value = {"id": 1, "name": "Alice"}

    # Act
    result = user_service.create_user("Alice")

    # Assert
    assert result.name == "Alice"
    mock_db.insert.assert_called_once()

# Use parametrize for varying inputs with same logic
@pytest.mark.parametrize("invalid_name", ["", None, "x" * 256])
def test_create_user_invalid_name_raises(user_service, invalid_name):
    with pytest.raises(ValidationError):
        user_service.create_user(invalid_name)

Do NOT mock:

  • Pydantic models - instantiate them directly
  • Dataclasses - use real instances
  • Pure functions in the same module

JavaScript/TypeScript (Jest/Vitest)

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { UserService } from './user-service';

// Mock external module
vi.mock('./api-client', () => ({
  ApiClient: vi.fn().mockImplementation(() => ({
    post: vi.fn(),
  })),
}));

describe('UserService', () => {
  let service: UserService;
  let mockApiClient: MockedObject<ApiClient>;

  beforeEach(() => {
    mockApiClient = new ApiClient() as MockedObject<ApiClient>;
    service = new UserService(mockApiClient);
  });

  it('creates user with valid input', async () => {
    mockApiClient.post.mockResolvedValue({ id: 1, name: 'Alice' });

    const result = await service.createUser('Alice');

    expect(result.name).toBe('Alice');
    expect(mockApiClient.post).toHaveBeenCalledOnce();
  });
});

Go (testing + testify)

package user

import (
    "testing"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/mock"
)

// Mock for external dependency
type MockDB struct {
    mock.Mock
}

func (m *MockDB) Insert(data map[string]any) (map[string]any, error) {
    args := m.Called(data)
    return args.Get(0).(map[string]any), args.Error(1)
}

func TestCreateUser_ValidInput_ReturnsUser(t *testing.T) {
    // Arrange
    mockDB := new(MockDB)
    mockDB.On("Insert", mock.Anything).Return(map[string]any{"id": 1, "name": "Alice"}, nil)
    service := NewUserService(mockDB)

    // Act
    result, err := service.CreateUser("Alice")

    // Assert
    assert.NoError(t, err)
    assert.Equal(t, "Alice", result.Name)
    mockDB.AssertExpectations(t)
}

Test Structure (AAA Pattern)

Always organize tests with clear sections:

  1. Arrange - Set up test data and mocks
  2. Act - Execute the code under test
  3. Assert - Verify the results

Anti-Patterns to Avoid

  1. Testing implementation details - Test behavior, not how it's achieved
  2. Excessive mocking - If everything is mocked, you're not testing real behavior
  3. One assertion per test dogma - Multiple related assertions in one test is fine
  4. Testing private methods directly - Always go through public API
  5. Duplicating tests for trivial variations - Use parametrized tests for input variations
  6. Mocking what you own - Prefer real implementations of your own simple classes