テスト方針
Bookmark CLI Extension のTDD方針、テスト対象、レイヤー別の確認範囲を定義します。
This content is for v1.3.1. Switch to the latest version for up-to-date documentation.
このページでは、Bookmark CLI Extensionのテスト方針を定義します。
基本方針は、Kent BeckのTDDを小さく適用し、Domain層の純粋関数を厚くテストすることです。
Domain層の純粋関数にはテストを書きます。
テストは仕様を固定するために書きます。
Domain層はfunctional coreとして扱い、入力と出力の対応をテストします。
不要な網羅ではなく、仕様上意味のあるケースだけを残します。
Chrome API、DOM、storage、時刻、乱数へ直接依存する処理はDomain層に置きません。
stream libraryを導入した場合も、Domain層のテストはplain dataの入出力を確認します。
Application層はPortをmockしてuse caseの分岐を確認します。
Infrastructure層は薄く保ち、Chrome APIとのadapter境界を確認します。
Presentation層は表示用view modelとキーバインドの状態遷移を確認します。
UI componentの分割方針は UI実装方針 で管理します。
TDDサイクル
Section titled “TDDサイクル”実装は次の順番で進めます。
- 失敗する最小のテストを書く
- そのテストを通す最小実装を書く
- 仕様を壊さずに整理する
- 不要なテストケースを削る
- 次の振る舞いへ進む
先に大きな抽象を作りません。
重複や複雑さが実際に見えてから抽象化します。
レイヤー別テスト
Section titled “レイヤー別テスト”| レイヤー | 主な対象 | 方針 |
|---|---|---|
| Domain | 純粋関数、値の正規化、検索、path解決 | 厚くテストする |
| Application | use case、CommandResult、Port失敗時の分岐 | Portをmockする |
| Infrastructure | Chrome API adapter、storage adapter | 薄く確認する |
| Presentation | view model、キーバインド、表示状態 | 状態遷移を中心に確認する |
| E2E | 主要sliceの通し動作 | v1後半で最小限追加する |
Domain層
Section titled “Domain層”Domain層はもっとも厚くテストします。
対象は次のとおりです。
- Bookmark Tree正規化
FolderPath生成- path解決
- fuzzy検索
- 仮想タグ正規化
- Result Listの番号解決
- 結果選択
- 利用統計の並び順
同じ入力に対して同じ出力を返すことを確認します。
外部APIのmockは使いません。
map、filter、flatMap、reduce を使う場合でも、配列操作の実装詳細ではなく、変換結果をテストします。
Application層
Section titled “Application層”Application層はuse caseの分岐を確認します。
対象は次のとおりです。
findBookmarksgoBookmarkchangeCurrentDirectorymarkCurrentTabaddVirtualTagsmoveBookmarkremoveBookmarkrenameBookmark
Portはmockまたはfakeで差し替えます。
Chrome APIの具体的な戻り値ではなく、Portが返すDomain寄りの値を使います。
正常系、代表的な異常系、書き込みの有無を確認します。
Infrastructure層
Section titled “Infrastructure層”Infrastructure層はadapter境界を確認します。
対象は次のとおりです。
- Chrome Bookmarks API adapter
- Chrome Storage API adapter
- TabContext adapter
Chrome API由来の失敗は、Application層で扱えるerror codeへ変換します。
chrome.storage.local から読み込んだraw valueは、typia validatorを通した結果だけをApplication層へ渡します。
typiaそのものの生成codeはテスト対象にしません。
storage adapterのwrapper、migration、fallback分岐をテストします。
Infrastructure層では複雑な分岐を持たせません。
複雑な変換が必要な場合は、Domain層またはApplication層の純粋関数へ切り出します。
Presentation層
Section titled “Presentation層”Presentation層はUIの状態変化を確認します。
UI componentはStory Firstで作り、Storybook上で状態を確認してからentrypointへ組み込みます。
RxJSのようなstream libraryを導入した場合は、streamそのものではなく、入力eventからview modelまたはCommandResultへ至る境界をテストします。
対象は次のとおりです。
- CommandResultから結果一覧view modelへの変換
- Powerline風prompt表示
- plain text fallback
- React componentのprops境界
- Popup設定画面のshortcut表示
- Popupからshortcut設定画面を開くadapter境界
- Popup設定画面のcommand alias表示
- command aliasの正規化、保存、展開
- command abbreviationの正規化、保存、空白入力時展開、Enter確定時展開
- abbreviation展開後の
clearによるscrollback transcript削除 - command aliasとcommand abbreviation補完候補
alias/unaliascommand parseralias/unaliascommand executorabbr/unabbrcommand parserabbr/unabbrcommand executorcopycommand parsercopycommand executorとClipboard adapter境界pwd | copyとls | copyのpipe copy- terminal surfaceのcommand input focus保持
- resultを持たないstatusやerrorの次行output表示
- URL result faviconをtitle/url stackの左で縦中央配置するlayout
- command transcriptの追加と保持件数
clearによるcommand transcript削除- command実行後のterminal viewport最下部追従
- command suggestionのprompt直下floating表示
- command suggestion overlay位置計算
- 空入力ではcommand suggestionを表示しないこと
- 上キー、下キー、
Ctrl+p、Ctrl+nの履歴移動 Ctrl+rによるCLI入力履歴のfloating一覧表示- CLI入力履歴一覧の新しい順表示と入力値による絞り込み
Ctrl+a、Ctrl+e、Ctrl+u、Ctrl+k、Ctrl+wの入力編集- 空promptの
Ctrl+dによるCLI window close - command suggestionのprefix一致
cd ./による現在ディレクトリ配下folder suggestionls -aによるdot始まりentry表示ls -lとllによる詳細表示- URL resultのfavicon URL生成とlocal環境でのplain text fallback
Tabによる補完候補の順方向選択Shift+Tabによる補完候補の逆方向選択Tabによる選択中suggestionの表示範囲追従Enterによる選択中補完候補の確定Escによる候補選択の解除
見た目そのものより、状態と表示用データの整合性を優先します。
E2Eはv1後半で最小限追加します。
最初からE2Eを厚くしません。
候補は次のとおりです。
- Dedicated extension pageを開ける
findの結果が表示されるgoでBookmark URLを開けるmarkでCLI起動元タブを保存できるrmが確認待ちでy/yesの場合だけ削除するrm -fが確認なしで削除するrmがfolder対象の場合は-rなしで削除しないrm -rがfolder対象の場合は確認待ちに入り、承認後にsubtree削除するrm -rfがfolder対象の場合は確認なしでsubtree削除する
E2Eはブラウザ拡張の統合確認として扱います。
Domainの詳細な仕様確認は単体テストで行います。
テストデータ
Section titled “テストデータ”テストでは小さなBookmark Treeを使います。
1つのテストに必要なnodeだけを含めます。
巨大なfixtureは避けます。
共通fixtureを使う場合も、テストの意図が読める名前にします。
優先して書くテスト
Section titled “優先して書くテスト”Slice 1では、次のテストを優先します。
- Bookmark TreeをBookmark EntryとFolder Entryへ正規化できる
- folder pathを生成できる
- Fuse.jsへ渡す検索対象がtitle、folder path、urlを含む
- Fuse.jsのscoreをCommandResultの詳細表示用scoreへ変換できる
- folder path一致が検索結果へ反映される
find #tagが仮想タグで絞り込むgoの候補がない場合はnot_foundを返す
Slice 3では、次のテストを優先します。
chrome.storage.localのraw valueをunknownとして扱う- 不正な保存データを初期値または
storage_failedへ変換できる - migration後の保存データをtypia validatorへ渡せる
- typia validation成功時だけ
ExtensionStateとして扱える
Slice 2以降は、実装ロードマップの完了条件に合わせて追加します。
テストしないこと
Section titled “テストしないこと”Chrome Bookmarks APIそのものの挙動はテストしません。
Chrome Extensions Storage APIそのものの永続化性能はテストしません。
typiaが生成するvalidatorの内部実装はテストしません。
typia wrapperに渡す入力、成功時の型境界、失敗時のfallbackをテストします。
Fuse.jsそのもののscore計算はテストしません。
Fuse.js wrapperの入力変換、出力変換、仮想タグfilterをテストします。
Nerd Fontの描画品質は単体テストしません。
ただし、初期表示でfont依存glyphを出さないことはcomponent testで検証します。
CSSの見た目は、必要になった時点でStorybookやブラウザ確認へ寄せます。
Storybookで確認できる状態は、component testで重複して確認しません。
テスト方針としての完了条件は次のとおりです。
- Domain層の主要な純粋関数にテストがある
- Application層の主要use caseにPort mockのテストがある
mkdir、mv、renameの即時実行とrmの確認待ちをテストしている- storage migration、schema検証、初期化をテストしている
- E2Eは主要sliceに絞っている