
Unit Testing Framework
- 450 installs
- 305 repo stars
- Updated March 4, 2026
- aj-geddes/useful-ai-prompts
unit-testing-framework is a testing prompt skill that stands up or extends unit test suites with consistent patterns, mocks, and coverage goals for developers preparing features to merge or release.
About
unit-testing-framework is a useful-ai-prompts skill that helps developers bootstrap or expand unit test infrastructure with consistent patterns, mock strategies, and coverage targets. The skill guides framework selection, test file structure, assertion style, and isolation techniques so new features ship with regression protection instead of ad-hoc test additions. Developers invoke it before merging significant features or cutting a release candidate when test gaps would block confident deployment. Output includes scaffolded test files, mock patterns for async dependencies, and coverage goals aligned to critical code paths.
- Framework selection guidance
- Mock and fixture patterns
- Coverage-oriented test design
- Arrange-act-assert templates
- CI-friendly test organization
Unit Testing Framework by the numbers
- 450 all-time installs (skills.sh)
- Ranked #626 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 unit-testing-frameworkAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 450 |
|---|---|
| repo stars | ★ 305 |
| Last updated | March 4, 2026 |
| Repository | aj-geddes/useful-ai-prompts ↗ |
How do you set up a unit testing framework?
Stand up or extend unit test suites with consistent patterns, mocks, and coverage goals before merging features or cutting a release candidate.
Who is it for?
Developers adding regression protection before a merge or release when the codebase lacks consistent unit test patterns or coverage.
Skip if: Skip unit-testing-framework for end-to-end browser testing, load testing, or projects that already have a mature test harness with enforced coverage gates.
When should I use this skill?
User needs to set up unit tests, add mocks, define coverage goals, or extend a test suite before merging or releasing
What you get
Unit test suite scaffold, mock patterns, coverage targets, and test file structure
- unit test scaffold
- mock pattern templates
- coverage target plan
Files
Unit Testing Framework
Table of Contents
Overview
Write effective unit tests that are fast, isolated, readable, and maintainable following industry best practices and AAA (Arrange-Act-Assert) pattern.
When to Use
- Writing tests for new code
- Improving test coverage
- Establishing testing standards
- Refactoring with test safety
- Implementing TDD (Test-Driven Development)
- Creating test utilities and mocks
Quick Start
Minimal working example:
// Jest/JavaScript example
describe("UserService", () => {
describe("createUser", () => {
it("should create user with valid data", async () => {
// Arrange - Set up test data and dependencies
const userData = {
email: "john@example.com",
firstName: "John",
lastName: "Doe",
};
const mockDatabase = createMockDatabase();
const service = new UserService(mockDatabase);
// Act - Execute the function being tested
const result = await service.createUser(userData);
// Assert - Verify the outcome
expect(result.id).toBeDefined();
expect(result.email).toBe("john@example.com");
expect(mockDatabase.save).toHaveBeenCalledWith(
expect.objectContaining(userData),
);
});
});
});Reference Guides
Detailed implementations in the references/ directory:
| Guide | Contents |
|---|---|
| Test Structure (AAA Pattern) | Test Structure (AAA Pattern) |
| Test Cases by Language | Test Cases by Language |
| Mocking & Test Doubles | Mocking & Test Doubles |
| Testing Async Code | Testing Async Code, Test Coverage |
| Testing Edge Cases | Testing Edge Cases |
| Example: Complete Test Suite | import { UserService } from "./user-service"; |
Best Practices
✅ DO
- Write tests before or alongside code (TDD)
- Test one thing per test
- Use descriptive test names
- Follow AAA pattern
- Test edge cases and error conditions
- Keep tests isolated and independent
- Use setup/teardown appropriately
- Mock external dependencies
- Aim for high coverage on critical paths
- Make tests fast (< 10ms each)
- Use parameterized tests for similar cases
- Test public interfaces, not implementation
❌ DON'T
- Test implementation details
- Write tests that depend on each other
- Ignore failing tests
- Test third-party library code
- Use real databases/APIs in unit tests
- Make tests too complex
- Skip edge cases
- Forget to clean up resources
- Test everything (focus on business logic)
- Write flaky tests
Example: Complete Test Suite
// user-service.test.ts
import { UserService } from "./user-service";
import { Database } from "./database";
import { EmailService } from "./email-service";
// Mock dependencies
jest.mock("./database");
jest.mock("./email-service");
describe("UserService", () => {
let userService: UserService;
let mockDatabase: jest.Mocked<Database>;
let mockEmailService: jest.Mocked<EmailService>;
beforeEach(() => {
mockDatabase = new Database() as jest.Mocked<Database>;
mockEmailService = new EmailService() as jest.Mocked<EmailService>;
userService = new UserService(mockDatabase, mockEmailService);
});
afterEach(() => {
jest.clearAllMocks();
});
describe("createUser", () => {
const validUserData = {
email: "john@example.com",
firstName: "John",
lastName: "Doe",
};
it("should create user successfully", async () => {
// Arrange
const savedUser = { id: "123", ...validUserData };
mockDatabase.save.mockResolvedValue(savedUser);
// Act
const result = await userService.createUser(validUserData);
// Assert
expect(result).toEqual(savedUser);
expect(mockDatabase.save).toHaveBeenCalledWith(
expect.objectContaining(validUserData),
);
expect(mockEmailService.sendWelcomeEmail).toHaveBeenCalledWith(
validUserData.email,
);
});
it("should throw ValidationError for invalid email", async () => {
const invalidData = { ...validUserData, email: "invalid" };
await expect(userService.createUser(invalidData)).rejects.toThrow(
"Invalid email format",
);
expect(mockDatabase.save).not.toHaveBeenCalled();
});
it("should handle database errors", async () => {
mockDatabase.save.mockRejectedValue(new Error("DB Error"));
await expect(userService.createUser(validUserData)).rejects.toThrow(
"Failed to create user",
);
});
it("should continue even if welcome email fails", async () => {
const savedUser = { id: "123", ...validUserData };
mockDatabase.save.mockResolvedValue(savedUser);
mockEmailService.sendWelcomeEmail.mockRejectedValue(
new Error("Email failed"),
);
const result = await userService.createUser(validUserData);
expect(result).toEqual(savedUser);
// User still created even though email failed
});
});
describe("getUserById", () => {
it("should return user when found", async () => {
const user = { id: "123", email: "john@example.com" };
mockDatabase.findById.mockResolvedValue(user);
const result = await userService.getUserById("123");
expect(result).toEqual(user);
});
it("should throw NotFoundError when user not found", async () => {
mockDatabase.findById.mockResolvedValue(null);
await expect(userService.getUserById("999")).rejects.toThrow(
"User not found",
);
});
});
});Mocking & Test Doubles
Mocking & Test Doubles
Mock External Dependencies
// Mock database
const mockDatabase = {
save: jest.fn().mockResolvedValue({ id: "123" }),
findById: jest.fn().mockResolvedValue({ id: "123", name: "John" }),
delete: jest.fn().mockResolvedValue(true),
};
// Mock HTTP client
jest.mock("axios");
axios.get.mockResolvedValue({ data: { users: [] } });
// Spy on methods
const spy = jest.spyOn(userService, "sendEmail");
expect(spy).toHaveBeenCalledWith("john@example.com", "Welcome");Python Mocking
from unittest.mock import Mock, patch, MagicMock
def test_send_email(mocker):
"""Test email sending with mocked SMTP"""
# Mock the SMTP client
mock_smtp = mocker.patch('smtplib.SMTP')
service = EmailService()
# Act
service.send_email('test@example.com', 'Subject', 'Body')
# Assert
mock_smtp.return_value.send_message.assert_called_once()
@patch('requests.get')
def test_fetch_user_data(mock_get):
"""Test API call with mocked requests"""
mock_get.return_value.json.return_value = {'id': 1, 'name': 'John'}
user = fetch_user_data(1)
assert user['name'] == 'John'
mock_get.assert_called_with('https://api.example.com/users/1')Test Cases by Language
Test Cases by Language
JavaScript/TypeScript (Jest)
import { Calculator } from "./calculator";
describe("Calculator", () => {
let calculator: Calculator;
beforeEach(() => {
calculator = new Calculator();
});
describe("add", () => {
it("should add two positive numbers", () => {
expect(calculator.add(2, 3)).toBe(5);
});
it("should handle negative numbers", () => {
expect(calculator.add(-2, 3)).toBe(1);
expect(calculator.add(-2, -3)).toBe(-5);
});
it("should handle zero", () => {
expect(calculator.add(0, 5)).toBe(5);
expect(calculator.add(5, 0)).toBe(5);
});
});
describe("divide", () => {
it("should divide numbers correctly", () => {
expect(calculator.divide(10, 2)).toBe(5);
});
it("should throw error when dividing by zero", () => {
expect(() => calculator.divide(10, 0)).toThrow("Division by zero");
});
it("should handle decimal results", () => {
expect(calculator.divide(10, 3)).toBeCloseTo(3.333, 2);
});
});
});Python (pytest)
import pytest
from user_service import UserService, ValidationError
class TestUserService:
@pytest.fixture
def service(self, mock_database):
"""Fixture to create UserService instance"""
return UserService(mock_database)
@pytest.fixture
def valid_user_data(self):
return {
'email': 'john@example.com',
'first_name': 'John',
'last_name': 'Doe'
}
def test_create_user_with_valid_data(self, service, valid_user_data):
"""Should create user with valid input"""
# Act
user = service.create_user(valid_user_data)
# Assert
assert user.id is not None
assert user.email == 'john@example.com'
assert user.first_name == 'John'
def test_create_user_with_invalid_email(self, service):
"""Should raise ValidationError for invalid email"""
invalid_data = {'email': 'invalid', 'first_name': 'John'}
with pytest.raises(ValidationError) as exc_info:
service.create_user(invalid_data)
assert 'email' in str(exc_info.value)
@pytest.mark.parametrize('email,expected', [
('user@example.com', True),
('invalid', False),
('', False),
(None, False),
])
def test_email_validation(self, service, email, expected):
"""Should validate email formats correctly"""
assert service.validate_email(email) == expectedJava (JUnit 5)
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
class UserServiceTest {
private UserService userService;
private UserRepository mockRepository;
@BeforeEach
void setUp() {
mockRepository = mock(UserRepository.class);
userService = new UserService(mockRepository);
}
@Test
@DisplayName("Should create user with valid data")
void testCreateUserWithValidData() {
// Arrange
UserDto userDto = new UserDto("john@example.com", "John", "Doe");
User savedUser = new User(1L, "john@example.com", "John", "Doe");
when(mockRepository.save(any(User.class))).thenReturn(savedUser);
// Act
User result = userService.createUser(userDto);
// Assert
assertNotNull(result.getId());
assertEquals("john@example.com", result.getEmail());
verify(mockRepository, times(1)).save(any(User.class));
}
@Test
@DisplayName("Should throw ValidationException for invalid email")
void testCreateUserWithInvalidEmail() {
UserDto userDto = new UserDto("invalid", "John", "Doe");
ValidationException exception = assertThrows(
ValidationException.class,
() -> userService.createUser(userDto)
);
assertTrue(exception.getMessage().contains("email"));
}
@ParameterizedTest
@ValueSource(strings = {"user@example.com", "test@domain.co.uk"})
@DisplayName("Should validate correct email formats")
void testValidEmailFormats(String email) {
assertTrue(userService.validateEmail(email));
}
@ParameterizedTest
@ValueSource(strings = {"invalid", "", "no-at-sign.com"})
@DisplayName("Should reject invalid email formats")
void testInvalidEmailFormats(String email) {
assertFalse(userService.validateEmail(email));
}
}Test Structure (AAA Pattern)
Test Structure (AAA Pattern)
// Jest/JavaScript example
describe("UserService", () => {
describe("createUser", () => {
it("should create user with valid data", async () => {
// Arrange - Set up test data and dependencies
const userData = {
email: "john@example.com",
firstName: "John",
lastName: "Doe",
};
const mockDatabase = createMockDatabase();
const service = new UserService(mockDatabase);
// Act - Execute the function being tested
const result = await service.createUser(userData);
// Assert - Verify the outcome
expect(result.id).toBeDefined();
expect(result.email).toBe("john@example.com");
expect(mockDatabase.save).toHaveBeenCalledWith(
expect.objectContaining(userData),
);
});
});
});Testing Async Code
Testing Async Code
// Jest async/await
it("should fetch user data", async () => {
const user = await fetchUser("123");
expect(user.id).toBe("123");
});
// Testing promises
it("should resolve with user data", () => {
return fetchUser("123").then((user) => {
expect(user.id).toBe("123");
});
});
// Testing rejection
it("should reject with error for invalid ID", async () => {
await expect(fetchUser("invalid")).rejects.toThrow("User not found");
});Test Coverage
# JavaScript (Jest)
npm test -- --coverage
# Python (pytest with coverage)
pytest --cov=src --cov-report=html
# Java (Maven)
mvn test jacoco:reportCoverage Goals:
- Statements: 80%+ covered
- Branches: 75%+ covered
- Functions: 85%+ covered
- Lines: 80%+ covered
Testing Edge Cases
Testing Edge Cases
describe("Edge Cases", () => {
it("should handle null input", () => {
expect(processData(null)).toBeNull();
});
it("should handle undefined input", () => {
expect(processData(undefined)).toBeUndefined();
});
it("should handle empty string", () => {
expect(processData("")).toBe("");
});
it("should handle empty array", () => {
expect(processData([])).toEqual([]);
});
it("should handle large numbers", () => {
expect(calculate(Number.MAX_SAFE_INTEGER)).toBeDefined();
});
it("should handle special characters", () => {
expect(sanitize('<script>alert("xss")</script>')).toBe(
"<script>alert("xss")</script>",
);
});
});#!/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
FAQ
What does unit-testing-framework help set up?
unit-testing-framework scaffolds unit test infrastructure—framework config, test file layout, mock patterns for async dependencies, and coverage targets—so features merge with consistent regression protection instead of one-off test additions.
When should unit-testing-framework be invoked?
unit-testing-framework fits before merging significant features or cutting a release candidate when test gaps would block confident deployment. The skill standardizes patterns across an existing or greenfield test suite.