test-generation
4
总安装量
3
周安装量
#53516
全站排名
安装命令
npx skills add https://github.com/protagonistss/ithinku-plugins --skill test-generation
Agent 安装分布
opencode
2
claude-code
2
antigravity
2
gemini-cli
1
Skill 文档
åå æµè¯çææè½
è¿ä¸ªæè½è´è´£åææºä»£ç å¹¶çæå¯¹åºçåå æµè¯ç¨ä¾ãæ¯æå¤ç§ç¼ç¨è¯è¨åæµè¯æ¡æ¶ã
æ ¸å¿è½å
1. 代ç åæ
- ASTè§£æï¼è¯å«å½æ°ãç±»ãæ¹æ³
- åæå½æ°ç¾åååæ°ç±»å
- è¯å«ä¾èµå ³ç³»åå¯¼å ¥æ¨¡å
- æ£æµå¼æ¥å½æ°åPromise使ç¨
2. æµè¯åºæ¯çæ
- æ£å¸¸æµç¨æµè¯ï¼Happy Pathï¼
- è¾¹çæ¡ä»¶æµè¯ï¼Boundary Valuesï¼
- å¼å¸¸æ 嵿µè¯ï¼Error Casesï¼
- åæ°éªè¯æµè¯
3. æµè¯ä»£ç çæ
- æ ¹æ®éæ©çæ¡æ¶çææµè¯ä»£ç
- çæåéçæµè¯åç§°åæè¿°
- æ·»å å¿ è¦çè®¾ç½®åæ¸ ç代ç
- çæææä¹çæè¨
æ¯æçæ¡æ¶
JavaScript/TypeScript
- Jest – ææµè¡çJavaScriptæµè¯æ¡æ¶
- Vitest – ç°ä»£åçViteåçæµè¯æ¡æ¶
- Mocha – çµæ´»çæµè¯æ¡æ¶
- Jasmine – è¡ä¸ºé©±å¨çå¼åæ¡æ¶
Python
- pytest – åè½å¼ºå¤§çæµè¯æ¡æ¶
- unittest – Pythonæ ååºæµè¯æ¡æ¶
- nose2 – unittestçæ©å±
Java
- JUnit 5 – ç°ä»£Javaæµè¯æ¡æ¶
- TestNG – æµè¯ä¸ä¸ä»£æ¡æ¶
- Mockito – 强大çMockæ¡æ¶
å ¶ä»è¯è¨
- Go (testing)
- C# (xUnit, NUnit)
- Ruby (RSpec, Minitest)
ä½¿ç¨æ¹æ³
åºç¡ä½¿ç¨
# çæåä¸ªå½æ°çæµè¯
/test src/utils/calculator.js --function add --framework vitest
# çææ´ä¸ªæä»¶çæµè¯
/test src/services/userService.js --framework jest --mocks
é«çº§é项
# å
å«è¦ççåæ
/test src/api/userController.js --framework jest --coverage
# çæè¾¹ç弿µè¯
/test src/utils/validator.js --edge-cases
# åªçæå¼å¸¸æµè¯
/test src/services/payment.js --error-only
æµè¯æ¨¡æ¿ç¤ºä¾
JavaScript/TypeScript – Vitest
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { UserService } from '../src/services/UserService';
describe('UserService', () => {
let userService: UserService;
let mockDb: any;
beforeEach(() => {
mockDb = {
find: vi.fn(),
create: vi.fn(),
update: vi.fn(),
delete: vi.fn()
};
userService = new UserService(mockDb);
});
describe('getUserById', () => {
it('should return user when found', async () => {
// Arrange
const userId = '123';
const expectedUser = { id: userId, name: 'John' };
mockDb.find.mockResolvedValue(expectedUser);
// Act
const result = await userService.getUserById(userId);
// Assert
expect(result).toEqual(expectedUser);
expect(mockDb.find).toHaveBeenCalledWith({ id: userId });
});
it('should return null when user not found', async () => {
// Arrange
const userId = '999';
mockDb.find.mockResolvedValue(null);
// Act
const result = await userService.getUserById(userId);
// Assert
expect(result).toBeNull();
});
});
});
Python – pytest
import pytest
from unittest.mock import Mock, patch
from services.user_service import UserService
class TestUserService:
@pytest.fixture
def user_service(self):
with patch('services.user_service.Database') as mock_db:
yield UserService(mock_db)
def test_get_user_by_id_success(self, user_service):
"""Test getting user with valid ID"""
# Arrange
user_id = 123
expected_user = {"id": user_id, "name": "John"}
user_service.db.find.return_value = expected_user
# Act
result = user_service.get_user_by_id(user_id)
# Assert
assert result == expected_user
user_service.db.find.assert_called_once_with({"id": user_id})
def test_get_user_by_id_not_found(self, user_service):
"""Test getting non-existent user"""
# Arrange
user_id = 999
user_service.db.find.return_value = None
# Act
result = user_service.get_user_by_id(user_id)
# Assert
assert result is None
æµè¯æ°æ®çæ
èªå¨çææµè¯æ°æ®
// æ ¹æ®ç±»åçææµè¯æ°æ®
const testData = {
string: ["hello", "", "a".repeat(255), "ç¹æ®å符"],
number: [0, 1, -1, 100, Number.MAX_SAFE_INTEGER],
boolean: [true, false],
array: [[], [1], [1, 2, 3], Array(1000).fill(0)],
object: [{}, { key: "value" }, null, undefined]
};
// è¾¹çå¼çæ
const boundaries = {
string: ["", "a", "a".repeat(255), "a".repeat(256)],
number: [Number.MIN_VALUE, -1, 0, 1, Number.MAX_VALUE],
array: [[] , [1], [1000]],
};
Mockçç¥
èªå¨Mockå¤é¨ä¾èµ
- è¯å«å¤é¨æ¨¡åå¯¼å ¥
- èªå¨çæMock代ç
- é ç½®Mockè¿åå¼
- éªè¯Mockè°ç¨
Mock示ä¾
// èªå¨çæçMock
jest.mock('../src/utils/logger', () => ({
logger: {
info: jest.fn(),
error: jest.fn(),
warn: jest.fn()
}
}));
// æµè¯ä¸éªè¯Mockè°ç¨
expect(logger.info).toHaveBeenCalledWith('User created successfully');
è¦ççä¼å
æºè½æµè¯è¡¥å
- åæä»£ç è¦ççæ¥å
- è¯å«æªæµè¯ç忝
- èªå¨çæè¡¥å æµè¯ç¨ä¾
- ä¼åæµè¯æ°æ®ç»å
è¦ççç®æ
- è¯å¥è¦çç > 90%
- 忝è¦çç > 85%
- 彿°è¦çç > 95%
- è¡è¦çç > 90%
æä½³å®è·µ
1. æµè¯å½åè§è
// â
好çå½å
it('should create user with valid data');
it('should throw error when email already exists');
// â é¿å
çå½å
it('test1');
it('user creation test');
2. AAA模å¼
it('should calculate discount correctly', () => {
// Arrange - å夿µè¯æ°æ®
const price = 100;
const discountRate = 0.1;
// Act - æ§è¡è¢«æµä»£ç
const result = calculateDiscount(price, discountRate);
// Assert - éªè¯ç»æ
expect(result).toBe(90);
});
3. æµè¯é离
- æ¯ä¸ªæµè¯ç¬ç«è¿è¡
- 使ç¨beforeEach/afterEachæ¸ ç
- é¿å æµè¯é´çä¾èµ
4. ææä¹çæè¨
// â
å
·ä½çæè¨
expect(user.email).toMatch(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
// â æ¨¡ç³çæè¨
expect(user).toBeDefined();
常è§é®é¢å¤ç
1. 弿¥ä»£ç æµè¯
// Promise
it('should resolve with data', async () => {
const result = await fetchData();
expect(result).toEqual(expectedData);
});
// Callback
it('should call callback', (done) => {
fetchData((data) => {
expect(data).toBeDefined();
done();
});
});
2. é误å¤çæµè¯
it('should throw error for invalid input', () => {
expect(() => validateEmail('invalid')).toThrow();
});
it('should reject promise on error', async () => {
await expect(asyncOperation()).rejects.toThrow('Error message');
});
3. æ¶é´ç¸å ³æµè¯
// 使ç¨åæ¶é´
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
it('should debounce function calls', async () => {
const debouncedFn = debounce(originalFn, 100);
debouncedFn();
vi.advanceTimersByTime(50);
expect(originalFn).not.toHaveBeenCalled();
vi.advanceTimersByTime(50);
expect(originalFn).toHaveBeenCalledTimes(1);
});
éæå½ä»¤
è¿ä¸ªæè½ä¸å ¶ä»å½ä»¤éæï¼
/test– çææµè¯ç¨ä¾/mock– çæMockæ°æ®/coverage– åææµè¯è¦çç
éè¿æºè½åæå模æ¿åçæï¼å¸®å©å¼åè å¿«éç¼åé«è´¨éçåå æµè¯ã