testする対象を見極める
#WIP
タイトル
ページ分割
前提
test codeを書きすぎないようにする
同じ目的を達成できるならば、コードは少ない方が良い
適切な箇所を、適切な分だけテストする
test codeを書く前にすべきこともある
型を正しくする
test codeを減らす工夫をする
test coverageに拘りすぎないようにする
見つけたバグをさっさと直してリリースすればいいみたいな気持ちもある
今までに一度もfailしたことのないテストって存在してる価値があるのか、みたいな感覚もある(言い過ぎ)
大幅に改修する際に安心感がある
というかどのみち同じチェックを手動でやらないといけないなら、それを全部テストに書いときゃ良い、という気もする
まあそれでも必要になったときに書きゃ良い、とも言えるかもしれない
Test Codeを書く目的を考える
将来のための保険としてのテスト
regressionを回避するため
testの偽陰性を抑えるために書く
意図せず壊れることを防ぐ
安全にぶっ壊せる仕組みを作っておく
過去に生じた問題を再度起こさないため
一度バグったことがある箇所
説明としてのテスト
仕様を列挙して明示する
いくつかの満たすべき条件がある際に、それをテストで明示する
コメントで明示しても効力にならないので、型とテストで明示する
この関数が満たすべき要件は5つあると言った場合に、それぞれに対してtest caseを書いときゃ良い
読む人もそれを見れば理解できる
使い方を示す
その関数の使用方法が分かりづらいものは、テストで使い方を明示する
そもそもわかりやすくしろ、というのはもちろんあるmrsekut.icon
testの目的は証拠を通じてステークホルダーの信頼を高めること
テストコードがなかった時の以下の時間を減らす
バグ修正にかかる時間
必要な文書を書く時間
設計にかかる時間
これらの時間よりもテストコードの記述、実行、メンテにかける時間の方が短くないと意味がない
上記の目的を達成するためにどこにtestを書くべきか
regressionを回避するためには、以下を意識する
/mrsekut-book-4839981728/113 (4.1 良い単体テストを構成する4本の柱)
そのtestで実行される(プロダクション)コードの量
そのコードの複雑さ
そのコードが扱っているドメインの重要性
コードベースの特に重要な部分のみをテストする
そのコードがバグったときの影響の大きさを意識する
外部から持ち込んだコード
library、API
testの偽陰性を意識する
バグが存在していることに気付かない、ということを避ける
逆に言えば、できるだけバグを検出するために書く、ということ
まずは型で検証できないところをしたい
I/Oとか
TypeScriptを使っている場合
ランタイムエラーになるようなところ
ルーティングなど、ページ遷移してるかどうかはテストしたい
これはViewの話になるのか
フォームのvalidation
逆にこの辺って型検査ってできるのかな
型システムに正規表現がアレばいける
静的検査はできると思うが
上記の目的を達成するためにどこにtestを書かないべきか
テストの内容が自明すぎるもの
例えば、JSONで表現されたtableを見て値を返す関数などは、テストしようにもそもそもそのtableが間違っていたら無意味だし、テスト書く際の認知として無意味な感じがする
code of truthみたいな
プロダクションコードと同じことを別の書き方で表現してるだけのテストは各意味がない
regressionの保護の役に立たない
逆に言えば、テストコードを見れば、ビジネス要求が導き出せる
あえてアルゴリズムをテストしてるものは除く
感覚的にバグる未来が見えない関数、みたいなのがある
上記の目的を達成するためにどういう表現のtestを書くべきか
実装の安定した部分にのみ依存するようにする
つまりpublic interface
実装に変更があった場合にテストコードが影響しないようになる
リファクタリングへの耐性
testの偽陽性を意識する
テストケース自体が間違っている、ということを避ける
実装の詳細をtestしない
/mrsekut-book-4839981728/123
コツとして、「いったんどういうロジック7日は忘れる」みたいなのありそう
それの責務だけに着目する
その関数から最終的に得られる結果は何なのか、を考える
と、いうことをやれば、どんな抽象度にも応用できる?
感覚的にはviewとかusecaseが対象になりそうな気はする
コードの最終的な結果をテスト対象にするというのは指針になりそう
懸念点として、コーナーケースのテストがしづらそう、というのがある
複雑なロジックを3つ持っているやつをテストしようとすると、それぞれのコーナーケースを外から検証するのは難しそう
とも思うが、まあ別に必ず抽象度を上げた箇所のみをテストするというわけでもないか
black-box testをする
Test use cases, not code.
ref
ユースケースをテストする
black-box testの言い換え
信号対ノイズ比
迅速なフィードバック
保守のしやすさ
どういうtest caseを書くべきか
どういうテストケースを選択するのが良いのか難しい
適当に選んだ正常系のケースを書けばよいのか?
それがテストケースとして選ばれる意味合いがうすすぎる
テストコードの意図が伝わりづらそう
sum(a,b)のテストケースとして、無限にある選択肢の中からsum(1,2) == 3を選んだのはなぜ??という気持ちになる
test caseの決め方みたいなのを知りたい
それがテスト技法か
テストの良さの評価軸がいくつかある
テストとして存在する意味がある
例えば、型では表現できなかった不変条件のようなものをテストするとか
ロジックとして間違いやすそうな箇所をテストするとか
境界値とかそういうの
保守性が高い、リファクタリングしても壊れない
今実装中のそれに対して、テストが必要かどうか?を問う
自明すぎないか
抽象度を上げれば必要になりそうではないか
コツとしては、
将来、どのようにリファクタリングされるか、を考える
チェックと探索
test codeてやっているのは既知のことを高速にチェックしてるだけ
未知の部分はテストできていない
いま私は自動テストの話をしていますが、自動テストって結局のところテストじゃないよねみたいな話をよくされます。自動テストはテストを行ってるのではなくて、高速にチェックを行ってるんだよね、と言われます。
それはその通りです。テストというものは2つに分かれていて、それは「チェック」と「探索(Explore)」であると言われています。これは言い方を変えると「Known領域」(既知)と「Unknown領域」(未知)なんですね。
自動テストは既に分かっているものが、今もその通りである、ということを高速に確かめる最強の手段の一つです。既知を既知のままにし続ける。
それに対して、スキルのあるテストエンジニアが得意なものが未知のものを既知にしてくることですね。つまり、未知のバグを発見してくることです。これはものすごく価値のあることなんです。ref
/mrsekut-book-4839981728/157 (5.2 観察可能な振る舞い(observable behavior)と実装の詳細(implementation detail))
プロダクションコードの2軸
publicなAPI、privateなAPI
観察可能な振る舞い、実装の詳細
そのAPIをpublicにすることが適切なのか?を考える
/mrsekut-book-4839981728/159
いやぁ〜、にゅあんす
直接的には繋がりません。
と言われてもなあ
感覚でわかるけど、説明として適切だとは思えんmrsekut.icon
そのpublicなAPIは、以下のいずれかを満たしていないといけない
clientが目標を達成するために使う、publicな操作
clientが目標を達成するために使う、publicな状態