Agent skill
test-development-vanillacake369-tonys-nix
Stars
163
Forks
31
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/testing/test-development-vanillacake369-tonys-nix
SKILL.md
Test Development Methodology
This skill enables creation of comprehensive, project-appropriate tests by learning from existing test patterns and conventions.
Leverages: [codebase-analysis] skill for discovering testing frameworks and patterns.
Testing Philosophy
Pattern-Driven Testing
- Learn from existing tests: Match structure, naming, and assertions
- Framework agnostic: Adapt to any testing framework or methodology
- Project conventions: Follow discovered test organization
- Quality first: Robust coverage and validation
Test Coverage Principles
- Test what matters most for the project
- Follow project's testing pyramid (unit/integration/e2e ratio)
- Match existing coverage standards
- Ensure tests are maintainable and readable
Testing Workflow
Phase 1: Test Environment Discovery
Using [codebase-analysis]:
- Find tests: Locate all test files and directories
- Identify framework: Detect testing framework and runners
- Analyze structure: Learn test organization patterns
- Discover execution: Find test commands and scripts
- Understand coverage: Learn coverage tools and standards
Phase 2: Test Pattern Analysis
Study existing tests:
- Naming conventions: Test file and function naming
- Structure patterns: Setup/teardown, fixtures, helpers
- Assertion style: expect(), assert(), should(), etc.
- Test data: How fixtures and test data are managed
- Integration patterns: How tests interact with services
Phase 3: Test Implementation
Create tests matching patterns:
- Follow discovered test structure exactly
- Use same testing libraries and utilities
- Match naming and organization conventions
- Apply consistent assertion patterns
- Integrate with existing test data/fixtures
Framework Detection and Adaptation
JavaScript/TypeScript
typescript
// Detected: Jest framework (from jest.config.js, *.test.ts)
// Match existing pattern:
describe('ProductService', () => {
let service: ProductService;
let mockRepository: jest.Mocked<ProductRepository>;
beforeEach(() => {
mockRepository = {
findById: jest.fn(),
save: jest.fn(),
} as any;
service = new ProductService(mockRepository);
});
it('should return product when found', async () => {
// Arrange
const productId = 1;
const expectedProduct = { id: productId, name: 'Test' };
mockRepository.findById.mockResolvedValue(expectedProduct);
// Act
const result = await service.getProduct(productId);
// Assert
expect(result).toEqual(expectedProduct);
expect(mockRepository.findById).toHaveBeenCalledWith(productId);
});
});
Python
python
# Detected: pytest framework (from pytest.ini, conftest.py)
# Match existing pattern:
import pytest
from services.product_service import ProductService
class TestProductService:
@pytest.fixture
def service(self, mock_repository):
return ProductService(mock_repository)
@pytest.fixture
def mock_repository(self, mocker):
return mocker.Mock()
def test_get_product_returns_product_when_found(self, service, mock_repository):
# Arrange
product_id = 1
expected_product = Product(id=product_id, name="Test")
mock_repository.find_by_id.return_value = expected_product
# Act
result = service.get_product(product_id)
# Assert
assert result == expected_product
mock_repository.find_by_id.assert_called_once_with(product_id)
Go
go
// Detected: Standard go test framework (from *_test.go files)
// Match existing pattern:
package product
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
type MockRepository struct {
mock.Mock
}
func (m *MockRepository) FindByID(id int) (*Product, error) {
args := m.Called(id)
return args.Get(0).(*Product), args.Error(1)
}
func TestProductService_GetProduct_ReturnsProductWhenFound(t *testing.T) {
// Arrange
mockRepo := new(MockRepository)
service := NewProductService(mockRepo)
productID := 1
expectedProduct := &Product{ID: productID, Name: "Test"}
mockRepo.On("FindByID", productID).Return(expectedProduct, nil)
// Act
result, err := service.GetProduct(productID)
// Assert
assert.NoError(t, err)
assert.Equal(t, expectedProduct, result)
mockRepo.AssertExpectations(t)
}
Java
java
// Detected: JUnit 5 + Mockito (from @Test, @ExtendWith annotations)
// Match existing pattern:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.mockito.Mock;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class ProductServiceTest {
@Mock
private ProductRepository productRepository;
@InjectMocks
private ProductService productService;
@Test
@DisplayName("Should return product when found")
void getProduct_WhenProductExists_ReturnsProduct() {
// Arrange
Long productId = 1L;
Product expectedProduct = Product.builder()
.id(productId)
.name("Test Product")
.build();
when(productRepository.findById(productId))
.thenReturn(Optional.of(expectedProduct));
// Act
Product result = productService.getProduct(productId);
// Assert
assertThat(result).isEqualTo(expectedProduct);
verify(productRepository).findById(productId);
}
}
Test Pattern Matching
Test Naming Conventions
python
# Learn from existing tests:
# Pattern found: test_methodName_condition_expectedResult
# ✅ Match the pattern:
def test_createProduct_withValidData_returnsProduct():
pass
def test_createProduct_withDuplicateName_raisesValidationError():
pass
def test_createProduct_withNegativePrice_raisesValidationError():
pass
Test Organization
typescript
// Learn from existing tests:
// Pattern found: Describe blocks for class, nested for methods
// ✅ Match the structure:
describe('OrderService', () => {
describe('createOrder', () => {
it('should create order with valid data', () => {});
it('should throw error with invalid customer', () => {});
it('should throw error with empty items', () => {});
});
describe('cancelOrder', () => {
it('should cancel order when pending', () => {});
it('should throw error when already shipped', () => {});
});
});
Assertion Style Matching
javascript
// Learn from existing tests:
// Pattern found: expect() with matcher methods
// ✅ Match assertion style:
expect(result).toBe(expected);
expect(array).toHaveLength(3);
expect(object).toEqual({ id: 1, name: 'Test' });
expect(fn).toHaveBeenCalledWith(arg1, arg2);
// ❌ Don't use different style:
assert.equal(result, expected); // Wrong - project uses expect()
Test Data Management
python
# Learn from existing tests:
# Pattern found: Fixtures in conftest.py
# ✅ Follow existing fixture pattern:
# In conftest.py
@pytest.fixture
def valid_product_data():
return {
"name": "Test Product",
"price": 99.99,
"category": "Electronics"
}
# In test file
def test_create_product_success(valid_product_data):
product = create_product(valid_product_data)
assert product.name == valid_product_data["name"]
Coverage Strategies
Unit Testing
java
// Focus on single unit isolation
// Test all paths: happy path + error cases + edge cases
@Test
void calculateDiscount_RegularCustomer_Returns10Percent() {
// Test happy path
}
@Test
void calculateDiscount_NullCustomer_ThrowsException() {
// Test error case
}
@Test
void calculateDiscount_ZeroAmount_ReturnsZero() {
// Test edge case
}
Integration Testing
typescript
// Test component interactions
// Use project's integration test patterns
describe('OrderController Integration', () => {
let app: INestApplication;
let orderRepository: Repository<Order>;
beforeAll(async () => {
// Setup test database
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication();
await app.init();
});
it('should create order end-to-end', async () => {
const response = await request(app.getHttpServer())
.post('/orders')
.send({ customerId: 1, items: [...] })
.expect(201);
expect(response.body).toHaveProperty('id');
});
});
End-to-End Testing
python
# Detected: Selenium/Playwright for E2E
# Match existing E2E patterns
def test_user_can_complete_purchase_flow(browser):
# Navigate to product page
browser.goto("/products/1")
# Add to cart
browser.click("#add-to-cart")
# Proceed to checkout
browser.click("#checkout")
# Fill shipping info
browser.fill("#shipping-address", "123 Main St")
# Complete purchase
browser.click("#complete-order")
# Verify success
assert browser.is_visible("#order-confirmation")
Test Quality Standards
AAA Pattern (Arrange-Act-Assert)
go
func TestOrderService_ProcessOrder(t *testing.T) {
// Arrange
order := &Order{
ID: 1,
CustomerID: 100,
Items: []Item{{ProductID: 1, Quantity: 2}},
}
mockRepo := new(MockRepository)
service := NewOrderService(mockRepo)
// Act
result, err := service.ProcessOrder(order)
// Assert
assert.NoError(t, err)
assert.Equal(t, OrderStatus.Processing, result.Status)
}
Test Independence
python
# ✅ Each test is independent
class TestUserService:
def test_create_user(self):
service = UserService() # Fresh instance
user = service.create_user({"email": "test@example.com"})
assert user.email == "test@example.com"
def test_delete_user(self):
service = UserService() # Fresh instance
# Test doesn't depend on test_create_user
pass
Clear Test Failures
typescript
// ✅ Descriptive assertions that help debug failures
it('should calculate correct total with tax', () => {
const result = calculator.calculateTotal(100);
// Good: Clear what's being tested
expect(result.subtotal).toBe(100);
expect(result.tax).toBe(10);
expect(result.total).toBe(110);
// ❌ Bad: Unclear which part failed
// expect(result).toEqual({ subtotal: 100, tax: 10, total: 110 });
});
Test Execution Integration
Match Project Test Commands
bash
# Detect from package.json, Makefile, justfile, etc.
# Found in package.json:
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"
}
# Ensure new tests work with existing commands
npm test # Must pass
npm run test:coverage # Must maintain coverage
CI/CD Integration
yaml
# Learn from existing .github/workflows/test.yml
# Ensure new tests integrate with CI pipeline
# Existing CI runs:
# - npm test
# - npm run lint
# - npm run build
# New tests must pass all these checks
Quality Checklist
Before finalizing tests:
- Test structure matches existing tests
- Naming follows project conventions
- Assertions use same style as project
- Test data follows existing patterns
- All tests pass when run
- Tests are independent and isolated
- Test failures provide clear diagnostics
- Coverage meets project standards
- Tests integrate with existing CI/CD
Anti-Patterns to Avoid
❌ Testing Implementation Details:
javascript
// Wrong - testing internal state
expect(service.internalCache.size).toBe(3);
// Right - testing behavior
expect(service.getUsers()).toHaveLength(3);
❌ Fragile Tests:
python
# Wrong - breaks with minor changes
assert user.created_at == datetime(2024, 1, 1, 12, 30, 45)
# Right - tests what matters
assert user.created_at is not None
assert user.created_at <= datetime.now()
❌ Dependent Tests:
java
// Wrong - tests depend on order
@Test
void test1_createUser() { ... }
@Test
void test2_updateUser() { // Depends on test1
// Breaks if test1 fails or runs separately
}
Remember: Great tests are readable, maintainable, and follow project patterns. Use [codebase-analysis] to discover testing conventions, then create tests that feel native to the project's testing culture.
Didn't find tool you were looking for?