[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6XCAGDWF83FWDWW5G9JA3B3":3,"skill-same:01M6XCAGDWF83FWDWW5G9JA3B3":83},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":34,"publishedAt":55,"linkOnly":56,"markdownContent":57,"markdownBody":58,"frontMatter":59,"refName":60,"commitSha":61,"skillDirectory":62,"forksCount":63,"repositoryHtmlUrl":64,"repositoryHomepageUrl":6,"ownerHtmlUrl":65,"ownerBlogUrl":66,"ownerDescription":67,"updatedAt":68,"install":69,"resources":82},"01M6XCAGDWF83FWDWW5G9JA3B3","test-design",null,"How to derive tests from a spec. Covers extracting test cases from Use Case extensions, GWT scenarios, and Design by Contract invariants. Core insight: the test oracle is an invariant — tests find their value in checking exception branches and properties that must always hold, not in re-stating the happy path. Trigger on: test generation, write tests, test design, integration test, 写测试, 测试设计, test from spec, test oracle, invariant, property test, 不变量.","Lincyaw\u002Fworkbuddy","Lincyaw","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F53161583?v=4","01M6XC87YTNETZ3AARKMHXJYJR","Aoyang Fang","01M6XC882ZSY5XBX2W6S88AGNH",2,"Apache-2.0","https:\u002F\u002Fgithub.com\u002FLincyaw\u002Fworkbuddy\u002Fblob\u002Fmain\u002Fdeploy\u002Fagentm\u002Fskills\u002Ftest-design\u002FSKILL.md",[18,23,26,31],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",{"categoryNo":32,"categoryName":33,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000037","律师与法务",[35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54],"design","test","test design","value","testing","test cases","path","invariants","re","extracting","how to","trigger","tests","branches","integration test","write","how","core","write tests","oracle","2026-11-10 10:12:30",false,"---\nname: test-design\ndescription: >\n  How to derive tests from a spec. Covers extracting test cases from\n  Use Case extensions, GWT scenarios, and Design by Contract invariants.\n  Core insight: the test oracle is an invariant — tests find their\n  value in checking exception branches and properties that must always\n  hold, not in re-stating the happy path. Trigger on: test generation,\n  write tests, test design, integration test, 写测试, 测试设计,\n  test from spec, test oracle, invariant, property test, 不变量.\n---\n\n# Test Design Guide\n\nTests are derived from the spec, not from the code. The test-gen\nagent writes tests without seeing any implementation.\n\nThe fundamental insight: **a test oracle is an invariant.** Every\nuseful test checks that some property holds (or is violated in a\nspecific way). The happy path is usually obvious and low-value — the\nreal testing power is in exception branches (what should NOT happen)\nand invariants (what should ALWAYS hold).\n\n## What to test, ordered by value\n\n### 1. Exception branches (highest value)\n\nEvery Use Case extension and every error-raising precondition is an\nexception branch. These are where bugs hide — the happy path gets\nexercised by every demo and manual test, but the `*a. Database\nunavailable at any step` extension only fires in production at 3am.\n\nFrom a Use Case:\n```\nExtension 2a: Scope not in allowed set → 400\nExtension 5a: Key quota exhausted → 429\nExtension *a: Database unavailable → 503, no partial state\n```\n\nEach becomes a test:\n```python\ndef test_ext_2a_invalid_scope_rejected():\n    response = create_api_key(scopes=[\"admin\"])\n    assert response.status == 400\n    assert \"invalid scope\" in response.body[\"error\"]\n\ndef test_ext_5a_quota_exhausted():\n    for _ in range(10):\n        create_api_key(scopes=[\"read\"])\n    response = create_api_key(scopes=[\"read\"])\n    assert response.status == 429\n\ndef test_ext_star_a_db_unavailable_no_partial_state():\n    with mock_db_failure():\n        response = create_api_key(scopes=[\"read\"])\n    assert response.status == 503\n    assert count_keys_in_db() == 0  # no partial state\n```\n\n### 2. Invariants (highest leverage)\n\nA Contract invariant holds after EVERY public method call. Testing\nit once is nice; testing it across random operation sequences is\npowerful — this is property-based testing.\n\nFrom a Contract:\n```\nInvariants:\n- total_value = sum(order.price * order.qty for order in orders)\n- All orders have unique IDs\n- No order has qty \u003C= 0\n```\n\nThe invariant test:\n```python\nfrom hypothesis import given, strategies as st\n\n@given(operations=st.lists(st.one_of(\n    st.tuples(st.just(\"add\"), st.integers(1, 1000), st.integers(1, 100)),\n    st.tuples(st.just(\"cancel\"), st.integers(0, 999)),\n)))\ndef test_invariant_total_value_consistent(operations):\n    book = OrderBook()\n    ids = []\n    for op in operations:\n        if op[0] == \"add\":\n            order_id = book.add_order(Order(price=op[1], qty=op[2]))\n            ids.append(order_id)\n        elif op[0] == \"cancel\" and ids:\n            idx = op[1] % len(ids)\n            try:\n                book.cancel_order(ids[idx])\n                ids.pop(idx)\n            except KeyError:\n                pass\n\n    # THE INVARIANT — must hold after any sequence of operations\n    expected = sum(o.price * o.qty for o in book.orders)\n    assert book.get_total_value() == expected\n    assert len(set(o.id for o in book.orders)) == len(book.orders)\n    assert all(o.qty > 0 for o in book.orders)\n```\n\nOne invariant test with random operations can find bugs that 50\nhand-written happy-path tests miss. The invariant is the oracle —\n\"this property must always hold\" is a stronger statement than \"this\nspecific input produces this specific output.\"\n\n### 3. Postcondition contracts (medium value)\n\nEach postcondition is a test: call the function with valid inputs,\nverify the postcondition holds.\n\nFrom a Contract:\n```\nadd_order(order):\n  postcondition: count increased by 1, total_value increased by\n  order.price * order.qty\n```\n\n```python\ndef test_add_order_postcondition():\n    book = OrderBook()\n    before_count = book.count\n    before_value = book.get_total_value()\n    order = Order(price=100, qty=2)\n\n    book.add_order(order)\n\n    assert book.count == before_count + 1\n    assert book.get_total_value() == before_value + 200\n```\n\n### 4. Precondition violations (medium value)\n\nEach precondition that raises should be tested:\n\n```\nadd_order(order):\n  precondition: order.qty > 0\n  raises: ValueError: qty \u003C= 0\n```\n\n```python\ndef test_add_order_precondition_zero_qty():\n    book = OrderBook()\n    with pytest.raises(ValueError):\n        book.add_order(Order(price=100, qty=0))\n\ndef test_add_order_precondition_negative_qty():\n    book = OrderBook()\n    with pytest.raises(ValueError):\n        book.add_order(Order(price=100, qty=-1))\n```\n\n### 5. GWT scenarios (direct translation)\n\nEach Given-When-Then scenario is already a test in prose form.\nTranslate directly:\n\n```\nScenario: Retry-After header value\n  Given client has exceeded their rate limit\n  And their window resets in 23 seconds\n  When they receive a 429 response\n  Then the Retry-After header value is \"23\"\n```\n\n```python\ndef test_gwt_retry_after_header():\n    # Given\n    limiter = RateLimiter(max_requests=1, window_seconds=30)\n    clock = MockClock(time=0)\n    limiter.check(\"c1\", clock=clock)  # exhaust quota\n    clock.advance(7)  # 7 seconds elapsed, 23 remaining\n\n    # When\n    result = limiter.check(\"c1\", clock=clock)\n\n    # Then\n    assert result.allowed is False\n    assert result.retry_after == 23\n```\n\n### 6. Happy path (lowest value, but don't skip)\n\nThe main success scenario of a Use Case. Low value because it's\nobvious, but you still need at least one test to verify the basic\nflow works:\n\n```python\ndef test_main_success_create_api_key():\n    response = create_api_key(scopes=[\"read\", \"write\"])\n    assert response.status == 201\n    assert \"secret\" in response.body\n    assert response.body[\"scopes\"] == [\"read\", \"write\"]\n```\n\nOne test, not ten variations. The exception branches and invariants\nare where your test budget should go.\n\n## Extraction rules by spec method\n\n### From Use Case → tests\n\n| Spec element | Test type | Naming |\n|---|---|---|\n| Main Success Scenario | 1 happy-path integration test | `test_uc_\u003Cname>_main_success` |\n| Extension Na | 1 test per extension | `test_uc_\u003Cname>_ext_\u003CN>\u003Cletter>_\u003Cdescription>` |\n| Postcondition | assert in happy-path test | (included in main success test) |\n| `*a` (at any step) | 1 test with fault injection | `test_uc_\u003Cname>_ext_star_a_\u003Cdescription>` |\n\n### From GWT → tests\n\nDirect 1:1 mapping. Each scenario is one test:\n\n| Spec element | Test type | Naming |\n|---|---|---|\n| Scenario | 1 test | `test_gwt_\u003Cscenario_name_snake_case>` |\n| Given | test setup \u002F fixtures | — |\n| When | function call \u002F action | — |\n| Then \u002F And | assertions | — |\n\n### From Contract → tests\n\n| Spec element | Test type | Naming |\n|---|---|---|\n| Invariant | 1 property-based test (hypothesis\u002Frapid) | `test_invariant_\u003Cdescription>` |\n| Postcondition | 1 test per method | `test_contract_\u003Cmethod>_postcondition` |\n| Precondition violation | 1 test per raises clause | `test_contract_\u003Cmethod>_rejects_\u003Ccondition>` |\n\n### From plain AC → tests\n\n| Spec element | Test type | Naming |\n|---|---|---|\n| AC-N | 1 test | `test_ac\u003CN>_\u003Cdescription>` |\n\n## Invariant-first test design\n\nWhen the spec has Design by Contract sections, start with the\ninvariants. They produce the highest-value tests.\n\nSteps:\n1. Read all invariants from the Contract section\n2. For each invariant, write a property-based test that:\n   - Creates the object\n   - Applies a random sequence of public method calls\n   - Asserts the invariant holds after each call (or at the end)\n3. Then write the per-method postcondition tests\n4. Then write the precondition violation tests\n5. Finally, write the GWT scenario tests and Use Case extension tests\n\nThis ordering front-loads the tests most likely to find real bugs.\n\n## When you don't have hypothesis\u002Fproperty-testing\n\nNot every language or project has property-based testing. The\ninvariant-first approach still works — just enumerate representative\nsequences manually:\n\n```python\ndef test_invariant_total_value_after_mixed_operations():\n    book = OrderBook()\n    book.add_order(Order(price=10, qty=5))   # total: 50\n    book.add_order(Order(price=20, qty=3))   # total: 110\n    id3 = book.add_order(Order(price=5, qty=10))  # total: 160\n    book.cancel_order(id3)                    # total: 110\n\n    assert book.get_total_value() == 110\n    assert book.count == 2\n    assert all(o.qty > 0 for o in book.orders)\n```\n\nLess powerful than random generation, but still tests the invariant\nacross a non-trivial sequence rather than testing one operation in\nisolation.\n\n## Verification: tests must fail without implementation\n\nAfter writing tests, run them. Every test MUST fail:\n\n- **ImportError** — module doesn't exist yet. Correct.\n- **AssertionError** — stub returns wrong values. Correct.\n- **AttributeError** — class\u002Ffunction doesn't exist. Correct.\n\nA test that passes without implementation is a bug. Investigate:\n- Feature already implemented? Check the codebase.\n- Assertion trivially true? (`assert x is not None`)\n- Wrong import? (testing an existing function with same name)\n\n## Test-to-spec traceability\n\nAfter writing tests, produce a mapping showing which spec elements\neach test covers:\n\n```\n## Test-to-Spec Mapping\n\n| Spec Element | Test | Oracle Type |\n|---|---|---|\n| UC ext 2a: invalid scope | test_uc_create_key_ext_2a | Exception branch |\n| UC ext *a: DB failure | test_uc_create_key_ext_star_a | Exception + invariant (no partial state) |\n| Contract invariant: total_value | test_invariant_total_value | Property-based invariant |\n| Contract pre: qty > 0 | test_contract_add_order_rejects_zero | Precondition violation |\n| GWT: retry-after header | test_gwt_retry_after_header | Behavioral scenario |\n| AC-1: config loaded | test_ac1_config_loaded | Direct assertion |\n```\n\nThe \"Oracle Type\" column makes explicit what kind of check the test\nperforms. This helps the review agent assess coverage quality — a\ntest suite with only \"Direct assertion\" oracles and no invariant or\nexception branch tests is weak regardless of line coverage numbers.\n\n## Anti-patterns\n\n**Testing the happy path N times.** Three tests that call `add_order`\nwith slightly different prices all test the same code path. Write one\nhappy-path test and spend the budget on exception branches.\n\n**Testing implementation details.** \"Assert internal `_counter` dict\nhas key 'c1'\" — this breaks when the implementation changes data\nstructures. Test the public postcondition: \"check('c1') returns False.\"\n\n**Invariant as a one-shot.** Writing `assert total == 50` after one\noperation tests a specific case, not the invariant. Apply a sequence\nof operations and check the invariant holds across all of them.\n\n**Mocking the thing under test.** Mock the clock, the database, the\nnetwork — not the class you're testing.\n\n**time.sleep in tests.** Flaky, slow. Inject a mock clock.\n\n**Tests that depend on execution order.** Each test must be\nindependently runnable. Use fresh fixtures.\n","# Test Design Guide\n\nTests are derived from the spec, not from the code. The test-gen\nagent writes tests without seeing any implementation.\n\nThe fundamental insight: **a test oracle is an invariant.** Every\nuseful test checks that some property holds (or is violated in a\nspecific way). The happy path is usually obvious and low-value — the\nreal testing power is in exception branches (what should NOT happen)\nand invariants (what should ALWAYS hold).\n\n## What to test, ordered by value\n\n### 1. Exception branches (highest value)\n\nEvery Use Case extension and every error-raising precondition is an\nexception branch. These are where bugs hide — the happy path gets\nexercised by every demo and manual test, but the `*a. Database\nunavailable at any step` extension only fires in production at 3am.\n\nFrom a Use Case:\n```\nExtension 2a: Scope not in allowed set → 400\nExtension 5a: Key quota exhausted → 429\nExtension *a: Database unavailable → 503, no partial state\n```\n\nEach becomes a test:\n```python\ndef test_ext_2a_invalid_scope_rejected():\n    response = create_api_key(scopes=[\"admin\"])\n    assert response.status == 400\n    assert \"invalid scope\" in response.body[\"error\"]\n\ndef test_ext_5a_quota_exhausted():\n    for _ in range(10):\n        create_api_key(scopes=[\"read\"])\n    response = create_api_key(scopes=[\"read\"])\n    assert response.status == 429\n\ndef test_ext_star_a_db_unavailable_no_partial_state():\n    with mock_db_failure():\n        response = create_api_key(scopes=[\"read\"])\n    assert response.status == 503\n    assert count_keys_in_db() == 0  # no partial state\n```\n\n### 2. Invariants (highest leverage)\n\nA Contract invariant holds after EVERY public method call. Testing\nit once is nice; testing it across random operation sequences is\npowerful — this is property-based testing.\n\nFrom a Contract:\n```\nInvariants:\n- total_value = sum(order.price * order.qty for order in orders)\n- All orders have unique IDs\n- No order has qty \u003C= 0\n```\n\nThe invariant test:\n```python\nfrom hypothesis import given, strategies as st\n\n@given(operations=st.lists(st.one_of(\n    st.tuples(st.just(\"add\"), st.integers(1, 1000), st.integers(1, 100)),\n    st.tuples(st.just(\"cancel\"), st.integers(0, 999)),\n)))\ndef test_invariant_total_value_consistent(operations):\n    book = OrderBook()\n    ids = []\n    for op in operations:\n        if op[0] == \"add\":\n            order_id = book.add_order(Order(price=op[1], qty=op[2]))\n            ids.append(order_id)\n        elif op[0] == \"cancel\" and ids:\n            idx = op[1] % len(ids)\n            try:\n                book.cancel_order(ids[idx])\n                ids.pop(idx)\n            except KeyError:\n                pass\n\n    # THE INVARIANT — must hold after any sequence of operations\n    expected = sum(o.price * o.qty for o in book.orders)\n    assert book.get_total_value() == expected\n    assert len(set(o.id for o in book.orders)) == len(book.orders)\n    assert all(o.qty > 0 for o in book.orders)\n```\n\nOne invariant test with random operations can find bugs that 50\nhand-written happy-path tests miss. The invariant is the oracle —\n\"this property must always hold\" is a stronger statement than \"this\nspecific input produces this specific output.\"\n\n### 3. Postcondition contracts (medium value)\n\nEach postcondition is a test: call the function with valid inputs,\nverify the postcondition holds.\n\nFrom a Contract:\n```\nadd_order(order):\n  postcondition: count increased by 1, total_value increased by\n  order.price * order.qty\n```\n\n```python\ndef test_add_order_postcondition():\n    book = OrderBook()\n    before_count = book.count\n    before_value = book.get_total_value()\n    order = Order(price=100, qty=2)\n\n    book.add_order(order)\n\n    assert book.count == before_count + 1\n    assert book.get_total_value() == before_value + 200\n```\n\n### 4. Precondition violations (medium value)\n\nEach precondition that raises should be tested:\n\n```\nadd_order(order):\n  precondition: order.qty > 0\n  raises: ValueError: qty \u003C= 0\n```\n\n```python\ndef test_add_order_precondition_zero_qty():\n    book = OrderBook()\n    with pytest.raises(ValueError):\n        book.add_order(Order(price=100, qty=0))\n\ndef test_add_order_precondition_negative_qty():\n    book = OrderBook()\n    with pytest.raises(ValueError):\n        book.add_order(Order(price=100, qty=-1))\n```\n\n### 5. GWT scenarios (direct translation)\n\nEach Given-When-Then scenario is already a test in prose form.\nTranslate directly:\n\n```\nScenario: Retry-After header value\n  Given client has exceeded their rate limit\n  And their window resets in 23 seconds\n  When they receive a 429 response\n  Then the Retry-After header value is \"23\"\n```\n\n```python\ndef test_gwt_retry_after_header():\n    # Given\n    limiter = RateLimiter(max_requests=1, window_seconds=30)\n    clock = MockClock(time=0)\n    limiter.check(\"c1\", clock=clock)  # exhaust quota\n    clock.advance(7)  # 7 seconds elapsed, 23 remaining\n\n    # When\n    result = limiter.check(\"c1\", clock=clock)\n\n    # Then\n    assert result.allowed is False\n    assert result.retry_after == 23\n```\n\n### 6. Happy path (lowest value, but don't skip)\n\nThe main success scenario of a Use Case. Low value because it's\nobvious, but you still need at least one test to verify the basic\nflow works:\n\n```python\ndef test_main_success_create_api_key():\n    response = create_api_key(scopes=[\"read\", \"write\"])\n    assert response.status == 201\n    assert \"secret\" in response.body\n    assert response.body[\"scopes\"] == [\"read\", \"write\"]\n```\n\nOne test, not ten variations. The exception branches and invariants\nare where your test budget should go.\n\n## Extraction rules by spec method\n\n### From Use Case → tests\n\n| Spec element | Test type | Naming |\n|---|---|---|\n| Main Success Scenario | 1 happy-path integration test | `test_uc_\u003Cname>_main_success` |\n| Extension Na | 1 test per extension | `test_uc_\u003Cname>_ext_\u003CN>\u003Cletter>_\u003Cdescription>` |\n| Postcondition | assert in happy-path test | (included in main success test) |\n| `*a` (at any step) | 1 test with fault injection | `test_uc_\u003Cname>_ext_star_a_\u003Cdescription>` |\n\n### From GWT → tests\n\nDirect 1:1 mapping. Each scenario is one test:\n\n| Spec element | Test type | Naming |\n|---|---|---|\n| Scenario | 1 test | `test_gwt_\u003Cscenario_name_snake_case>` |\n| Given | test setup \u002F fixtures | — |\n| When | function call \u002F action | — |\n| Then \u002F And | assertions | — |\n\n### From Contract → tests\n\n| Spec element | Test type | Naming |\n|---|---|---|\n| Invariant | 1 property-based test (hypothesis\u002Frapid) | `test_invariant_\u003Cdescription>` |\n| Postcondition | 1 test per method | `test_contract_\u003Cmethod>_postcondition` |\n| Precondition violation | 1 test per raises clause | `test_contract_\u003Cmethod>_rejects_\u003Ccondition>` |\n\n### From plain AC → tests\n\n| Spec element | Test type | Naming |\n|---|---|---|\n| AC-N | 1 test | `test_ac\u003CN>_\u003Cdescription>` |\n\n## Invariant-first test design\n\nWhen the spec has Design by Contract sections, start with the\ninvariants. They produce the highest-value tests.\n\nSteps:\n1. Read all invariants from the Contract section\n2. For each invariant, write a property-based test that:\n   - Creates the object\n   - Applies a random sequence of public method calls\n   - Asserts the invariant holds after each call (or at the end)\n3. Then write the per-method postcondition tests\n4. Then write the precondition violation tests\n5. Finally, write the GWT scenario tests and Use Case extension tests\n\nThis ordering front-loads the tests most likely to find real bugs.\n\n## When you don't have hypothesis\u002Fproperty-testing\n\nNot every language or project has property-based testing. The\ninvariant-first approach still works — just enumerate representative\nsequences manually:\n\n```python\ndef test_invariant_total_value_after_mixed_operations():\n    book = OrderBook()\n    book.add_order(Order(price=10, qty=5))   # total: 50\n    book.add_order(Order(price=20, qty=3))   # total: 110\n    id3 = book.add_order(Order(price=5, qty=10))  # total: 160\n    book.cancel_order(id3)                    # total: 110\n\n    assert book.get_total_value() == 110\n    assert book.count == 2\n    assert all(o.qty > 0 for o in book.orders)\n```\n\nLess powerful than random generation, but still tests the invariant\nacross a non-trivial sequence rather than testing one operation in\nisolation.\n\n## Verification: tests must fail without implementation\n\nAfter writing tests, run them. Every test MUST fail:\n\n- **ImportError** — module doesn't exist yet. Correct.\n- **AssertionError** — stub returns wrong values. Correct.\n- **AttributeError** — class\u002Ffunction doesn't exist. Correct.\n\nA test that passes without implementation is a bug. Investigate:\n- Feature already implemented? Check the codebase.\n- Assertion trivially true? (`assert x is not None`)\n- Wrong import? (testing an existing function with same name)\n\n## Test-to-spec traceability\n\nAfter writing tests, produce a mapping showing which spec elements\neach test covers:\n\n```\n## Test-to-Spec Mapping\n\n| Spec Element | Test | Oracle Type |\n|---|---|---|\n| UC ext 2a: invalid scope | test_uc_create_key_ext_2a | Exception branch |\n| UC ext *a: DB failure | test_uc_create_key_ext_star_a | Exception + invariant (no partial state) |\n| Contract invariant: total_value | test_invariant_total_value | Property-based invariant |\n| Contract pre: qty > 0 | test_contract_add_order_rejects_zero | Precondition violation |\n| GWT: retry-after header | test_gwt_retry_after_header | Behavioral scenario |\n| AC-1: config loaded | test_ac1_config_loaded | Direct assertion |\n```\n\nThe \"Oracle Type\" column makes explicit what kind of check the test\nperforms. This helps the review agent assess coverage quality — a\ntest suite with only \"Direct assertion\" oracles and no invariant or\nexception branch tests is weak regardless of line coverage numbers.\n\n## Anti-patterns\n\n**Testing the happy path N times.** Three tests that call `add_order`\nwith slightly different prices all test the same code path. Write one\nhappy-path test and spend the budget on exception branches.\n\n**Testing implementation details.** \"Assert internal `_counter` dict\nhas key 'c1'\" — this breaks when the implementation changes data\nstructures. Test the public postcondition: \"check('c1') returns False.\"\n\n**Invariant as a one-shot.** Writing `assert total == 50` after one\noperation tests a specific case, not the invariant. Apply a sequence\nof operations and check the invariant holds across all of them.\n\n**Mocking the thing under test.** Mock the clock, the database, the\nnetwork — not the class you're testing.\n\n**time.sleep in tests.** Flaky, slow. Inject a mock clock.\n\n**Tests that depend on execution order.** Each test must be\nindependently runnable. Use fresh fixtures.\n",{"name":5,"description":7},"main","b9778c800f442939b879c9a556dfb8d6f4a40971","deploy\u002Fagentm\u002Fskills\u002Ftest-design",1,"https:\u002F\u002Fgithub.com\u002FLincyaw\u002Fworkbuddy","https:\u002F\u002Fgithub.com\u002FLincyaw","http:\u002F\u002Fprofile.aoyangfang.top\u002F","Student in The Chinese University of Hong Kong, Shenzhen","2026-06-08 13:33:51",{"source":8,"skillName":5,"commands":70,"prompt":80,"zipAvailable":81},[71,74,77],{"tool":72,"command":73},"npx","npx skills add Lincyaw\u002Fworkbuddy --skill test-design",{"tool":75,"command":76},"bunx","bunx skills add Lincyaw\u002Fworkbuddy --skill test-design",{"tool":78,"command":79},"pnpm","pnpm dlx skills add Lincyaw\u002Fworkbuddy --skill test-design","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FLincyaw\u002Fworkbuddy\u002Fblob\u002Fmain\u002Fdeploy\u002Fagentm\u002Fskills\u002Ftest-design\u002FSKILL.md",true,[],[84,109,145,172,191,214],{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":90,"publishedAt":55},"01M6XCBSW1MMEAWEF38VX9NH3E","workbuddy-guide","Explain and operate workbuddy: what it is, which command to reach for, and where to find deeper references. **Trigger whenever the user mentions 'workbuddy' in any context** — including operational requests (register\u002Fonboard a repo, add\u002Fbind a worker, 注册仓库, 加仓库, 接入新仓库, onboard repo, set up worker), explanatory questions (how to use workbuddy, workbuddy guide, teach me workbuddy, 怎么用workbuddy, 使用指南), deployment\u002Frunning\u002Foperating\u002Fdebugging workbuddy, and questions about how issues\u002Ftasks are scheduled or how dependencies between issues work (depends_on, blocked, dependency gate, 依赖, 调度, 排队, '为什么没派发'), and questions about parallel-development workflows (rollouts:N fan-out, synthesize\u002Fsynthesis reduce step, cherry-pick, '并行开发', '多个方案', 'rollout'). Invoke this skill before running workbuddy CLI commands so the documented onboarding flow (coordinator register + worker repos add) and the dependency\u002Fscheduling model aren't re-derived from scratch.","https:\u002F\u002Fgithub.com\u002FLincyaw\u002Fworkbuddy\u002Fblob\u002Fmain\u002Fplugins\u002Fworkbuddy\u002Fskills\u002Fworkbuddy-guide\u002FSKILL.md",[],[91,92,93,94,95,96,97,98,99,100,101,102,45,103,104,43,105,106,107,108],"guide","workbuddy guide","debugging","issues","SET","model","pick","up","rollouts","deeper","worker","bind","operating","coordinator","operate","which","scheduled","invoke",{"skillNo":110,"name":111,"nameZh":6,"description":112,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":113,"categories":114,"keywords":124,"publishedAt":55},"01M6XCBM7B95PB3Q6PHZ3TCM7F","web-debug","Validate the workbuddy webui (SPA + auth + JSON API) end-to-end on the same machine workbuddy runs on, using browser-use's headless harness. Use when the user says 'verify the frontend', 'test the SPA', 'check dashboard loads', '前端验证', '验下 webui', or after merging changes that touch internal\u002Fwebui, web\u002F, or the auth\u002Fcookie path.","https:\u002F\u002Fgithub.com\u002FLincyaw\u002Fworkbuddy\u002Fblob\u002Fmain\u002Fplugins\u002Fworkbuddy\u002Fskills\u002Fweb-debug\u002FSKILL.md",[115,118,121],{"categoryNo":116,"categoryName":117,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":119,"categoryName":120,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":122,"categoryName":123,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000030","开发工程师",[125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144],"web","debug","web debug","frontend","auth","browser","harness","api","check","use","webui","spa","end","machine","touch","loads","headless","browser-use","using browser","when",{"skillNo":146,"name":147,"nameZh":6,"description":148,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":149,"categories":150,"keywords":154,"publishedAt":55},"01M6XCBFR925WJSWEYVHGSTT56","setup-repo","Configure a GitHub repository for workbuddy orchestration — creates labels, the two canonical agent configs (dev + review), workflow definitions, issue templates, and config.yaml. Use when the user says 'set up repo', 'configure repo for workbuddy', 'initialize workbuddy', '配置仓库', '初始化workbuddy', or wants to onboard a new repo.","https:\u002F\u002Fgithub.com\u002FLincyaw\u002Fworkbuddy\u002Fblob\u002Fmain\u002Fplugins\u002Fworkbuddy\u002Fskills\u002Fsetup-repo\u002FSKILL.md",[151],{"categoryNo":152,"categoryName":153,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[155,156,157,158,159,160,161,162,163,95,164,165,98,166,167,168,169,170,171,144],"setup","setup repo","repo","review","orchestration","workflow","config","dev","repository","configure","initialize","issue","new repo","初始化","canonical","for","labels",{"skillNo":173,"name":174,"nameZh":6,"description":175,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":176,"categories":177,"keywords":178,"publishedAt":55},"01M6XCBAEPZQTAS5FZYCPDEGAG","pipeline-monitor","Monitor the workbuddy agent pipeline, detect stuck issues, zombie processes, and missed redispatches. Works for both the 3-unit bundle (supervisor + coordinator + worker) and single-process `serve`. Use when the user says 'monitor the pipeline', 'check workbuddy status', '监工', '看看跑完了没', or asks to watch issue progress.","https:\u002F\u002Fgithub.com\u002FLincyaw\u002Fworkbuddy\u002Fblob\u002Fmain\u002Fplugins\u002Fworkbuddy\u002Fskills\u002Fpipeline-monitor\u002FSKILL.md",[],[179,180,181,182,94,183,133,134,166,184,101,185,186,187,188,104,189,170,190,144],"monitor","pipeline","pipeline monitor","status","supervisor","missed","watch","progress","detect","unit","agent pipeline","single",{"skillNo":192,"name":193,"nameZh":6,"description":194,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":195,"categories":196,"keywords":198,"publishedAt":55},"01M6XCB5RTYNH7QK9RQ5Z4B6NK","merge-flow","Merge a batch of approved workbuddy PRs into main: order them, resolve conflicts against design intent, validate post-merge health, and report. Use when the user asks to 'merge the batch', 'merge approved PRs', 'integrate finished issues', '批量合并', '处理冲突'; or when the merge-agent is invoked.","https:\u002F\u002Fgithub.com\u002FLincyaw\u002Fworkbuddy\u002Fblob\u002Fmain\u002Fplugins\u002Fworkbuddy\u002Fskills\u002Fmerge-flow\u002FSKILL.md",[197],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[199,200,201,35,202,203,94,204,205,206,134,207,208,209,210,60,211,212,213,144],"merge","flow","merge flow","validate","report","batch","health","user","integrate","resolve conflicts","conflicts","intent","post","design intent","prs",{"skillNo":215,"name":216,"nameZh":6,"description":217,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":218,"categories":219,"keywords":223,"publishedAt":55},"01M6XCB29F96RJ02Z3BXTAVYSB","deploy","Workbuddy deployment topology guide — explains the 3-unit bundle (supervisor + coordinator + worker), the rolling-restart property, and the cutover from the legacy single-process `serve` install. Use when the user says 'how should I deploy workbuddy', 'install workbuddy as a service', 'switch to bundle', 'rolling restart', '部署 workbuddy', '升级到 bundle'.","https:\u002F\u002Fgithub.com\u002FLincyaw\u002Fworkbuddy\u002Fblob\u002Fmain\u002Fplugins\u002Fworkbuddy\u002Fskills\u002Fdeploy\u002FSKILL.md",[220],{"categoryNo":221,"categoryName":222,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000011","运维与部署",[216,224,225,51,183,226,227,91,134,228,229,101,230,231,232,233,188,104,190,144],"deployment","topology","process","install","Legacy","switch","service","as","bundle","serve"]