smithery/ting-s515

bdd-unit-test

指定一或多個檔案並要求撰寫單? 根據 BDD(行為? 觸發? 即使只說「寫測試」或「補測試」,只要有指定目標檔案或貼上程式碼片段,也應載?

Installation

$ npx skills add smithery/ting-s515 --skill bdd-unit-test

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/ting-s515.

npx skills add smithery/ting-s515

Browse all from smithery/ting-s515

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 10,921 B
  • docs SUMMARY.md 196 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

單元測試撰寫指南(BDD 原則)

執行流程

  1. 判別語言:根據檔案副檔名判別程式語言,載入對應範例
  2. 分析原始碼:讀取一或多個指定檔案,識別所有公開方法、條件分支、邊界情況
  3. 列出測試場景:使用 BDD 格式列出所有需測試的場景(先輸出給用戶確認)
  4. 撰寫測試:根據確認的場景撰寫測試程式碼
  5. 輸出測試檔案:依據語言規範輸出到正確位置

測試範圍

✅ 包含

  • 純邏輯函數(計算、驗證、轉換)
  • 服務層方法(business logic)
  • 工具函數(utils/helpers)
  • 資料處理(parsing、formatting)
  • 狀態管理邏輯(非 UI 綁定部分)

❌ 不包含

  • UI 畫面測試:不測試 React/Vue 元件的渲染結果、DOM 結構
  • 純展示元件:若元件只負責靜態文字、圖片或樣式呈現,沒有業務邏輯、條件分支、狀態轉換或使用者互動,不需要撰寫單元測試
  • CSS class 驗證:不使用 querySelectorquerySelectorAllcontainer.querySelector 或其他 CSS selector 抓取 class、DOM 節點來驗證畫面
  • 視覺回歸測試:不測試樣式、佈局、截圖比對
  • E2E 測試:不測試完整使用者流程、瀏覽器互動
  • 整合測試:不測試多個模組的整合行為

UI 測試穩定性原則

  • 測試應驗證可觀察的功能行為,不要綁定容易因重構或樣式調整而變動的 CSS class、DOM 階層或 selector。
  • 禁止為了取得元素而使用 querySelectorquerySelectorAllcontainer.querySelector,以及以 .className[class*=...] 等 CSS selector 進行驗證。
  • 若元件確實包含互動或條件行為,優先使用可存取角色、名稱、標籤、文字或測試框架提供的語意查詢,例如 Testing Library 的 getByRolegetByLabelTextgetByText
  • 不驗證實作細節,例如 class 名稱、內部 DOM 包裝層數或純樣式切換;只驗證使用者可感知的結果與業務行為。
  • 分析目標檔案後若確認只是簡單畫面展示元件,場景分析應明確標示「不需要單元測試」並停止產生測試檔案。

語言判別規則

根據目標檔案的副檔名判別語言,分兩條路徑處理:

已知語言(有 reference 範例)

副檔名 語言 載入範例
.ts, .tsx TypeScript references/typescript-example.test.ts
.js, .jsx JavaScript references/typescript-example.test.ts
.cs C# references/csharp-example-test.cs
.java Java references/java-example-test.java
.py Python references/python-example-test.py
.dart Flutter/Dart references/flutter-example.dart

執行步驟:

  1. 取得目標檔案的副檔名
  2. 根據上表判別語言
  3. 讀取對應的 example 檔案作為撰寫測試的參考
  4. 依照該語言的規範(框架、命名、輸出位置)產出測試

未知語言(無 reference 範例,fallback)

副檔名不在上表時,直接以 LLM 通用知識處理:

  • 根據副檔名推斷語言與該語言主流測試框架(如 .dartflutter_test.rb → RSpec、.gotesting 套件)
  • 套用相同的 BDD 原則、Given/When/Then 命名、場景分類(Happy / Edge / Error)
  • 依該語言慣例決定檔案命名與輸出位置
  • 不讀取任何 reference 檔案,不需告知使用者

BDD 核心原則

Given-When-Then 結構

Given [前置條件/初始狀態]
When  [執行的動作/觸發事件]
Then  [預期結果/驗證行為]

測試場景分類(必須涵蓋)

分類 說明 範例
✅ Happy Path 正常流程、預期輸入 有效參數、正確格式
⚠️ Edge Cases 邊界條件 空值、最大/最小值、零
❌ Error Cases 異常處理 無效輸入、例外拋出
🔄 State Changes 狀態轉換 初始化、重置、更新

測試命名規範

採用 Given條件When動作Should預期行為 格式:

GivenNoItems_WhenGetList_ShouldReturnEmptyList
GivenNullInput_WhenValidate_ShouldThrowException
GivenItemsExist_WhenCalculateTotal_ShouldReturnCorrectSum

語言別測試規範

🟨 JavaScript/TypeScript (.ts, .tsx)

項目 規範
框架 Jest
檔案命名 [ComponentName].test.tsx
輸出位置 同目錄的 tests/ 資料夾
Mock 工具 jest.mock()
斷言風格 expect(result).toBe(expected)

結構範例:

describe('模組/元件名稱', () => {
  describe('方法名稱', () => {
    it('Given[條件]_When[動作]_Should[預期行為]', () => {
      // Given - 準備測試資料
      const input = { ... };

      // When - 執行被測方法
      const result = targetMethod(input);

      // Then - 驗證結果
      expect(result).toEqual(expected);
    });
  });
});

🟦 C# (.cs)

項目 規範
框架 xUnit
檔案命名 [ClassName]Test.cs
輸出位置 對應的 .Tests 專案資料夾
Mock 工具 Moq
斷言風格 Assert.Equal(expected, actual)

結構範例:

public class UserServiceTests
{
    [Fact]
    public void GivenUserExists_WhenGetUser_ShouldReturnUser()
    {
        // Given
        var mockRepo = new Mock<IUserRepository>();
        mockRepo.Setup(r => r.GetById(1)).Returns(new User { Id = 1 });
        var service = new UserService(mockRepo.Object);

        // When
        var result = service.GetUser(1);

        // Then
        Assert.NotNull(result);
        Assert.Equal(1, result.Id);
    }
}

☕ Java (.java)

項目 規範
框架 JUnit 5 / TestNG
檔案命名 [ClassName]Test.java
輸出位置 src/test/java/ 對應套件路徑
Mock 工具 Mockito, MockK (Kotlin)
斷言風格 AssertJ: assertThat(result).isEqualTo(expected)

結構範例:

@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

    @Mock
    private OrderRepository orderRepository;

    @InjectMocks
    private OrderService orderService;

    @Test
    @DisplayName("應該在訂單存在時返回訂單")
    void GivenOrderExists_WhenGetOrder_ShouldReturnOrder() {
        // Given - 設定 mock 行為
        Order expected = new Order(1L, "item");
        when(orderRepository.findById(1L)).thenReturn(Optional.of(expected));

        // When - 執行被測方法
        Order result = orderService.getOrder(1L);

        // Then - 驗證結果
        assertThat(result).isNotNull();
        assertThat(result.getId()).isEqualTo(1L);
    }
}

🐍 Python (.py)

項目 規範
框架 pytest / unittest
檔案命名 test[modulename].py
輸出位置 tests/ 資料夾,保持與 src 相同結構
Mock 工具 unittest.mock, pytest-mock
斷言風格 assert result == expected

結構範例:

import pytest
from unittest.mock import Mock, patch

class TestUserService:
    """UserService 單元測試"""

    def test_GivenUserExists_WhenGetUser_ShouldReturnUserData(self):
        """應該在用戶存在時返回用戶資料"""
        # Given
        mock_repo = Mock()
        mock_repo.get_by_id.return_value = {"id": 1, "name": "Test"}
        service = UserService(mock_repo)

        # When
        result = service.get_user(1)

        # Then
        assert result is not None
        assert result["id"] == 1

🐦 Flutter/Dart (.dart)

項目 規範
框架 flutter_test + mocktail
檔案命名 [classname]test.dart
輸出位置 test/ 資料夾,保持與 lib 相同結構
Mock 工具 mocktail(class MockX extends Mock implements X {}
斷言風格 expect(result, equals(expected))

結構範例:

void main() {
  late CartService cartService;
  late MockProductRepository mockProductRepo;

  setUp(() {
    mockProductRepo = MockProductRepository();
    cartService = CartService(mockProductRepo);
  });

  group('CartService', () {
    group('addItem', () {
      test('GivenProductExists_WhenAddItem_ShouldAddToCart', () {
        // Given
        when(() => mockProductRepo.findById(1)).thenReturn(product);

        // When
        final result = cartService.addItem(1, 2);

        // Then
        expect(result.items, hasLength(1));
      });
    });
  });
}

Mock 使用原則

何時使用 Mock

  • 📦 外部套件依賴(npm packages、第三方函式庫)
  • 🌐 外部 API 呼叫(HTTP requests)
  • 🗄️ 資料庫操作
  • 📁 檔案系統存取
  • ⏰ 時間相關函數(Date.now, datetime)
  • 🎲 隨機數生成

Mock 最佳實踐

  1. 只 Mock 直接依賴:不要 Mock 被測單元的內部實作
  2. 驗證互動:確認 Mock 被正確呼叫(次數、參數)
  3. 重置狀態:每個測試後清理 Mock 狀態
  4. 避免過度 Mock:過多 Mock 可能表示耦合度太高

輸出格式

執行此 skill 時,請依序輸出:

1️⃣ 場景分析

## 📋 測試場景分析

**目標檔案:** `path/to/file.ts`, `path/to/other.ts`(單檔時僅列一個)
**識別的公開方法:** methodA, methodB, methodC

### 測試場景列表

| # | 方法 | 場景類型 | 描述 |
|---|------|----------|------|
| 1 | methodA | ✅ Happy | 當輸入有效時應返回正確結果 |
| 2 | methodA | ⚠️ Edge | 當輸入為空時應返回空陣列 |
| 3 | methodA | ❌ Error | 當輸入為 null 時應拋出例外 |

確認以上場景後,我將開始撰寫測試。

2️⃣ 測試程式碼

依據確認的場景,輸出完整測試檔案,包含:

  • 必要的 import
  • 完整的測試結構
  • 每個測試的 Given/When/Then 註解

參考範例

根據判別的語言,讀取對應的範例檔案:

  • TypeScript/JavaScript: references/typescript-example.test.ts
  • C#: references/csharp-example-test.cs
  • Java: references/java-example-test.java
  • Python: references/python-example-test.py
  • Flutter/Dart: references/flutter-example.dart

注意:撰寫測試前必須先讀取對應語言的範例,確保遵循一致的風格與結構。