組織に自動テストを書く文化を根付かせる戦略
自動テストの評価
あれ
自動テストの隠れた利益って、プログラミング言語やライブラリに対する知識かもしれん。
テスト書くのは安全で、そこで試行錯誤すると安全に知識が増える。
あれ
テスト用のメールむずい。
サインアップまわりのテストを自動化したいけど、メールがフローにはさまってて、そこをいい感じにできなくてつんでる。
ポートフォワーディングか何かでSMTP用のポート露出して、メールサーバーをローカルでたてて、とか考えたけど、構成要素おおすぎて、めんどくさくてむりぽよになった。
Vitest
あれ
自動テストを回していると、CPUが100%に張り付いてしまう。コードを書いている時もコード生成AIがGPUをぶん回している。より性能のよいコンピューターがあれば、より速くソフトウェア開発が進むだろう。
ソフトウェア開発は手工業から機械工業へ移行しつつあると感じる。コンピューターはプログラマーにとっての道具を超えて、生産機械となりつつある。
良い単体テストが備える特性
あれ
定例会議中に自動テストのデモンストレーションのために、「ほらここをこう書き換えるとバグとして検知されるんですよ」ってやったら、ほんとにバグとして検知されて感動した。完璧にテストが機能しているし、カバレッジも高まってきているのを感じる。
事前準備もなく、流れで適当にコードを書き換えてバグらせたし、それでバグが検知されるだろうという確信があった。この「バグが検知されるだろうという確信」があることに対しても感動している。
あれ
互いに依存するパラメーターが6個ある機能のテストに必要なパターンをフェルミ推定したところ8万パターン必要という計算になった。どのパターンも、境界値や閏年となっており、バグの検出において重要な値になっている。
全てを手動で網羅しようとすると一週間はかかるため、代表的な900パターンの自動テストでお茶を濁した。
さらに、一部のパターンをコメントアウトし、200パターンが回帰テストされるようにした。
パラメーターの空間に対してテストの密度が低いので、この機能に対して将来にわたって「バグは起きない」という確信は持てない。祈るしかない。
さりとて、2-3年前の私は手動のテストしかしていなかったため、今よりはるかに低い密度のテストしかしていなかった。1/100程度のパターンしかテストしていなかったと思う。そんなテストでよくもまぁなんとかなっていたなと思うと同時に、現在が過剰品質になっている可能性がある。
一つの機能に対して900パターンの手動テストを品証の人に頼みつつ「これでも厳選したんですよ」などと言おうものなら、頭をはたかれるだろう。前に私がテスターをやっていた時は2人がかりで二週間かけて200件ほどのテスト数だった。
あれ
何もヒットしない検索結果画面を表示したくて、
ああああああああ
と適当に入力して検索したら、
ああああああああがヒットした。
ざけんな!って思った。
自動テストとかで一意な何かがほしいとき、UUIDを生成することがよくある。テスト用のSQLiteのDBファイルの名前とか。
というのをなんとなく想起した。
偽陰性
偽陰性(false-negative)は、検査対象が陽性であるにも関わらず、検査では陰性だと判定され、陽性だと判定されない状態を指す。
自動テストの文脈では、テスト対象の実装に不具合があるにも関わらず、テストケースが成功する状態を指す。すなわち、テストケースがテスト対象の不具合を検出できない状態となっている。
欠陥挿入
全体のテストスイートの1%程度になるにつれて、開発者がテストの失敗に反応しなくなる
テストへの信頼の喪失が起こると、エンジニアはテストの失敗に反応することをやめ、テストスイートの提供する価値が全部削がれてしまう
信頼不能性が1%に接近すると、テストは価値を失い始める
『自動テストに対して信頼がだんだん失われていく時とは』
Flaky Test
Flaky Testは検査結果が陰性と偽陽性の間を確率的に変化するテストケース。
Flaky Testは以下の点においてシステム開発に悪影響を与える。
- Flaky Testを通過するために再検査が必要と成るため、自動テストの時間を押し伸ばす要因となる
- 開発者が自動テストのテストケース群を信用しなくなり、自動テストのテストケースを保守する意欲を失わせる
- テストケースの失敗が偽陽性と真陽性のどちらなのかの区別が付きづらく、真陽性を取りこぼす可能性が上がり、本番環境に不具合があるコードを配備する可能性が高くなる
テストケースに関わる機材・コンポーネント・モジュール・システムの数が増えるほど、そのテストケースがFlaky Testになる傾向がある。
全体のテストスイートの1%程度になるにつれて、開発者がテストの失敗に反応しなくなると言われている。
偽陽性
偽陽性(false-positive)は、本当は検査対象が陽性ではないが、検査では陽性だと判定される状態を指す。
自動テストの文脈では、テスト対象の実装に問題が無いにも関わらず、テストケースが失敗する状態を指す。また、検査結果が陰性と偽陽性の間を確率的に変化するテストケースは、Flaky Testと呼ばれる。
VRT
Consumer Driven Contract Testing
「不具合の修正時には必ず先に不具合を再現する自動テストを書いてから修正する」
『Testable Lambda: Working Effectively with Legacy Lambda』
あれ
『自動テストに限界を感じた私がなぜ形式手法に魅了されたのか』
あれ
自動テストをやってるとテストケースからシステムの振る舞いがわかるのでコードレビューが楽で大変に良い。
テストコードに書かれている期待動作に変化があれば、そこを起点に議論ができる。
『t_wadaさんと「単体テストの使い方/考え方」の疑問点についてディスカッションしました』
Playwright
あれ
会社でシステムの改修にたいして、Backlogのチケット単位での試験のエビデンスが必要になったので、どうしてやろうかとなってる。
せっかく自動テストやっとるので、自動テストやってる箇所についてはエビデンスもいい感じに生成されて欲しい。
jestで差分テストやって、その結果をチケットにコピペでぺってはったるのが一番素朴な感じ。
Githubでプルリク作ったらJestが走って、プルリクのコメントでJestの実行結果のレポート出るみたいな感じにしたいっすね。
JestのHTML reporter色々あるけど、定番とか無さげ?jest-junitがJestの公式で言及されてるけど、出力がXMLなので扱いがめんどい。
あれ
作っているシステムがなかなか品証を通らずリリースできないでいる。
品証が通らなければリリースを翌週に延期してバクを直すのだが、時間が余って機能追加するものだからそれでまたバグるみたいなことを繰り返している。
自動テストを作ってもコレなので、システムの規模が大きくなると厄介だ。
なんとか今日中にバグを直して、品質保証して、翌週月曜日にリリースできるようにしたいけども、今日は午後から社員旅行で時間がなくて無理そう。
バグ直すだけならできると思うんだけど、自動テストの拡充チャンスなので、自動テスト化してから直したい。
あれ
CypressによるE2Eテストもgit commitの度に実行されるようにしてあったのだが、これはやめてしまった。リリース時のみ使用することとした。
まず時間がかかりすぎる。1ケースあたり1秒はかかる。複雑なことをすれば10秒20秒かかるのが当たり前になる。現時点で20のテストケースが作られており、全て実行されるまでトイレに行く時間程度はかかる。
次にAWS費用が高くついた。E2Eテストなので当然APIが叩かれ、DBにクエリが走り、ログが保存される。1日に15回ほどのgit commitをしたところ、その日のCloudWatchの費用がX USDを超え、予算超過のアラートが出た。E2Eテストが今月分の予算を食い尽くしてしまった。確かに開発速度と引き換えの必要経費と言える。日給XXX円と思えば破格だ。しかし今は上司が育休に入っており予算を拡大するには予算申請が社長に飛ぶ。社長の時間単価はX USDよりはるかに高い。あとなんか怖い。予算超過は年に均せばまだセーフということで、なんとか爪に火を灯して凌ごうとなった。
しかし、このみみっちい判断が社長の意にそぐわない可能性は高い。やるべきことをやってない。XXX円のために人件費を垂れ流している。いや、そこまで考えるのは追い込み過ぎか。現時点で十二分に開発速度は速い。
あれ
React Testing libraryによって100を超えるテストケースが実装された。10秒ほどでそのすべてが実行される。
コードの保存、コミット、プッシュのたびに自動テストが実行されるようにしてある。
テスト作成になれてきている。加えて、一度テストを作成した箇所はテストの追加が容易だ。だんだんとテスト作成速度が上がってきている。
あれ
Excelに記載してるテスト項目に対して自動テストのコードを紐付けて、自動テストできてない項目は手動テストする見たいなことがしたいんだけど、良い運用方法が思いつかない。
Excelからリンクか何かでいい感じに自動テストのコードが開けるとなお良い。
自動テストの方に名前だけの空テストコード作ってやればいいかしら。そんでもって自動テストの方で色々管理する方式。
あれ
「4回のテストで自動テストはペイする」ということで、「開発中の動作確認・git commit時の動作確認・git push時の動作確認・デプロイ時の動作確認で自動テストがつかえるので、実質1サイクルで自動テストはペイする」となった。
なので「バクを直すとき」「新機能を追加するとき」「リファクタリングするとき」に関連する自動テストを作るとコスパが良い。
React Testing Library
あれ
プロジェクトの自動テストが整ってきて嬉しい
デプロイ・git push・git commitのタイミングで自動テストが実行されるので、自動テストが腐らないぞ!
あれ
遺伝的アルゴリズムにしろ、遺伝的プログラミングにしろ、与えられた課題に有利なバグがあったら徹底活用してくるし、不利なバグがあったら徹底回避してくるので、バグの発見が難しい。内部で乱数が使われているのも輪をかけてバグの発見を難しくしてくる。
なので自動テストで一個づつ動いているか確認しようと思ったのだが、ちゃんと動いてるはずだったのに自動テスト書いたらpanicで全然動かへん。
なんで動いてるんだこいつ……
いや、なんかgo run
で動かすとバグんないんだけど、go test
するとバグる。なんだこれ、goroutine分からん。
やっぱりgoroutineというか並列処理みたいなことを再帰関数でやるってのは辞めた方が良い予感。ワシには難しすぎる問題になる。
func node_exec(node *Node, program Program, inputs *[constant.EMBEDDING_LENGTH + 1]int, input_map *map[int]int) int {
if node.Executed {
return node.Value
}
if node.Function < program.Static_functions_index_max {
node.Executed = true
node.Value = program.Functions[node.Function](inputs, input_map, &program.Queue, &program.Stack, 0, 0)
return node.Value
}
wg := sync.WaitGroup{}
node.Executed = true
arg1 := 0
arg2 := 0
wg.Add(2)
go func() {
arg1 = node_exec(&program.Nodes[node.Index1], program, inputs, input_map)
defer wg.Done()
}()
go func() {
arg2 = node_exec(&program.Nodes[node.Index2], program, inputs, input_map)
defer wg.Done()
}()
wg.Wait()
node.Value = program.Functions[node.Function](inputs, input_map, &program.Queue, &program.Stack, arg1, arg2)
return node.Value
}
あれ
ユニットテスト始めました
毎回AWSにデプロイして動作確認しなくて良くなったので体験が良い
待ち時間が減った
あれ
自動テストの損益分岐点は4回
『質とスピード(2020秋100分拡大版) / Quality and Speed 2020 Autumn Edition』
あれ
JavaScriptを書けば書くほど落とし穴を自分で掘ってる感じがする
Typescriptに変えよう🥺🥺🥺
Typescript勉強するか~~~~~~
puppeteerによる自動テストもやってみてるけど、早すぎた感
ライブラリに渡す引数に何渡せばいいかわかるし、タイポも減らせるし、バグを圧倒的に減らせたからオヌヌメ・・・!
拡張子をjsからtsに変えたら、至る所が真っ赤になってわろてる
お、tsへの移行が完了した。
300行のJavaScriptだったけど、TypeScriptへの移行に1.5時間かかった。
これから効率が良くなるので、これから取り戻せるはず。
各スプリントでリリースするにはテスト自動化が必須