LoginSignup
4
0

再考 テスト駆動開発

Last updated at Posted at 2024-03-10

Blog記事を読んで

【翻訳】テスト駆動開発の定義 - t-wadaのブログ
https://t-wada.hatenablog.jp/entry/canon-tdd-by-kent-beck

保守しやすく変化に強いソフトウェアを支える柱 自動テストとテスト駆動開発、その全体像 ~Software Design 2022年3月号「そろそろはじめるテスト駆動開発」より | gihyo.jp
https://gihyo.jp/article/2024/01/automated-test-and-tdd

自分自身のテスト駆動開発について再考してみました。

テスト駆動開発の誤解

  • 設計せずにきなりテストコードを書き始めること。
  • テスティングフレームワークを使う事を指す。
  • 最初にテストを書く
  • テストは開発者自身が書く
  • まず、テストを書いてから関数やコンポーネントを書く
  • テストを書けば信頼性が上がる。
  • テスト駆動開発は品質保証の手法である。
  • テストファーストとは、最初にテストコードを全部書いてから関数やコンポーネントのコードを書くこと。

これらをテスト駆動開発と誤解をしている人(=私)むけ

形から入るテスト駆動開発

一番単純なステップ

  1. 設計
  2. リスト
  3. レッド、グリーン、リファクタ(<これらを繰り返す)

以上

簡単な説明付きのステップ

  1. テストリストの作成
  2. 一つのテストを書く(レッド)
  3. テストを成功させる(グリーン)
  4. 必要に応じてリファクタリングを行う(リファクタリング)
  5. テストリストが空になるまでステップ2に戻って繰り返す

のステップを踏む

※テスト駆動開発は設計をしてからはじめます。

※テストリストはテストケースとも呼んでいます。

参考学習動画

TDD Boot Camp 2020 Online #1 基調講演/ライブコーディング - YouTube
https://www.youtube.com/watch?v=Q-FJ3XmFlT8

43分頃から

まず課題、問題があり、

1から100までの数をプリントするプログラムを書け。
ただし3の倍数のときは数の代わりに「Fizz」と、
5の倍数の時は「Buzz」とプリントし、
3と5両方の倍数の場合には「FizzBuzz」とプリントすること。

※この課題は、簡単な問題だが、プレッシャーがかかる状況で、解けるプログラマーが非常に少なかった・・・ということですごく有名になった。

実際にやってみると、FizzBuzz問題はテスト駆動開発でやってみるとかなり大変。

※AIならば1秒で解ける。

テスト駆動開発で解く

↑44:10秒ぐらい

分割統治

テストと実装を交互に行うことで、複雑なソフトウェアをより効率的に開発する方法です。

大きなアプリを作成する場合、それらを何らかの部分ごとに切り分けていけば、結局はAテストぐらいの簡単さに分割できる。

↓56:00ぐらい

TODO

====================================

テスト容易性:高 重要度:高

-[ ] 数を文字列に変換する
-[ ] 3の倍数のときは数の代わりに「Fizz」と変換する。
-[ ] 5の倍数の時は「Buzz」と変換する。
-[ ] 3と5両方の倍数のときは数の代わりに「FizzBuzz」に変換する。

テスト容易性:低 重要度:低
-[ ] 1からnまで
-[ ] 1から100まで
-[ ] プリントする

動画は続く・・・




詳細な説明付きのステップ

ステップ1:テストリスト

振る舞いの分析

あるシステムに振る舞いにおいて期待される動作をリストアップする。

振る舞いの変更が既存の動作を壊さないようにする方法をテストリストに追加する。

この段階では、具体的な実装方法ではなく、期待される動作に焦点を当てましょう。

してはいけないこと

実装の設計判断を混ぜ込む。

いきなりコードを書き始める。
※設計を済ませてから行いましょう。

テストリストを最後まで書いてしまう。

最初のテストを書く前に、すべてのテストケースを書き出す必要はありません。1つずつテストを書いていくことで、設計を改善しやすくなります。

ステップ2:ひとつテストを書く

準備と実行と検証(アサーション)が備わった、本当に自動化されたテストを「ひとつだけ」書きます。

最初は失敗するテストです。(レッド)

テストリストから次に書くテストを選び出すのは重要なスキルで、それは経験によってのみ得られます。

テストを選ぶ順番は、プログラミングの快適さと最終的な成果の両方に重大な影響を及ぼします。

プロからのアドバイス: 時には、テストコードをアサーションから書き始めて、上に向かって逆向きに書き進めてみよう。

※テストはきちんと書くのに越したことはないですが、1件だけでもいいです、0件よりはかなりマシです。

してはいけないこと

アサーションのないテストコードを書く
※カバレッジの率を上げたいだけの意味がないテストコードだ。

実際のテストコードは、必ずアサーションを含めて、期待される動作を明確に記述しましょう。

先にテストリストをすべてテストコード化する

最初からすべてのテストケースをコード化しようとすると、設計が固まってしまい、柔軟性に欠けてしまいます。1つずつテストを書いていくことで、必要に応じて設計を変更できます。

ステップ3:テストを成功させる

失敗するテストをひとつ書けたら、今度はシステムを変更してテストを成功させる。

レッド(テスト失敗)からグリーン(テスト成功)にする過程で新しいテストの必要性に気づいたら、それをテストリストに追加します。

プロからのアドバイス: 初めからやり直すが、今度は違う順番でテストを選んでみよう。
テストが成功したら「済」マークをつけてテストリストから取り消し線などで消します。
TODOリストアプリなどを使っている場合、テスト済みに移動させます。

してはいけないこと

アサーションを削除してテストを成功させる

テストを成功させるためには、コードを変更する必要があります。アサーションを削除するのは、問題を隠すだけの行為です。

テスト対象を実際に動かしたときの値をコピーして、テストコードの中の期待値にペーストしてしまうこと。
これではダブルチェックにならず、TDDの妥当性確認(validation)としての価値が台無しになってしまいます。

テストコードは、テスト対象の値に依存しない独立したコードである必要があります。

テストを書きながら、リファクタリングも一緒にやってしまう。

まずはテストを成功させることに集中し、その後、必要に応じてリファクタリングを行いましょう。

このやりかたが結局は脳にも優しい。

ステップ4:リファクタリングを行う

ここまできて、実装の設計判断を行いうようにします。

してはいけないこと

必要以上にリファクタリングをしない。

リファクタリングは、コードをよりシンプルで理解しやすいものにするために必要ですが、過剰なリファクタリングは時間の無駄です。

早すぎる抽象化、コードの共通化。

抽象化は、コードを再利用しやすくするために有効ですが、必要以上に抽象化すると、コードが複雑になり、理解しにくくなります。

ステップ5:テストリストが空になるまで繰り返す

コードの動作に対する不安が退屈に変わるまで、テストとコーディングを繰り返し続けます。

してはいけないこと

テストがすべて成功しても、コードの動作に対する不安が残っている場合は、追加のテストを書くことで、コードの信頼性を向上させます。

まず何を作るかを決めそれを設計書に書く。

設計を元に、テストリストを作る。

テストリストの中から「ひとつだけ」選び出し、
実際に、具体的で、実行可能なテストコードに翻訳する

テストリストが空になるまでステップ3に戻って繰り返す

以上




テストを使って開発するのに段階がある、
テスティングフレームワークツールを使うだけ、ドクトリンを守る、一部のいいとこ取りをする。

テスト駆動開発ではないが最低限やってほしいこと。

1.自動テスト
2.テストファースト
3.テスト駆動開発

の3段階に分ける

テスト駆動開発まで行かずとも、自動テストだけでも行えば十分に価値があります。


1つとは

テストリストを整理して、そのなかから1つを取り出す方法、取り出す成功率?は経験によって向上します。

慣れてくると、テストリストの優先順位付けはうまくなっていきます。
※動画を参考

テスト容易性を考え、簡単かつ重要度の高いものを上にする。

必要に応じてリファクタリングを行い、実装の設計を改善します。

※ステップ3だけが有名になりすぎましたが、ステップ2も同じぐらい重要です。

TDDの狙い

そのプログラマを支援して、システムを下記のような新たな状態に導くことです。

  • それまで動作していたものは引き続き全て動作する
  • 新しい振る舞いは期待通りに動作する
  • システムはさらなる変更の準備ができている
  • プログラマとその同僚は、上記の点に自信を持っている

インターフェイスと実装の分離

設計には2種類ある

  • ある振る舞いはどのように呼び出されるべきかの設計
  • システムはその振る舞いをどう実装するべきかの設計

この2つは論理設計と物理設計と呼ばれ、
それらは決して混ぜてはならないと言われた


テストリスト

テストシナリオのリスト

テストファースト、テストファーストプログラミング(Test-First Programming)

必ずテストを先に書くようにする。

これで、テスト対象のコードは必ずテスト可能になります。

※開発する本人以外の人が先にテストコードを書くこともあります。他の人が書く場合はテスト駆動開発の構成要素にはなりません

自動テスト(Automated Test)

テスティングフレームワークを使ってテストコードを書く

テスティングフレームワークの機能を使うことでテストを自動で実行できるようになる。

誰が書いても構いませんし、いつ書いても構いません

自動テストの条件

自己検証可能

テストは成功か失敗かの2つの結果だけ。

そしてテスト自身が人間の目を介さずに成功か失敗かを自分で判断できる。

人間が目で見て期待した結果と同じかどうか確かめる場合は違います。

繰り返し可能 Repeatable

テストを誰が、いつ、どこで実行しても同じように動く

テスト実行後に手動でデータをリセットしたり、ファイルを消したりしている場合はそのテストは条件を満たしていない。

自動テストに強く推奨される性質

独立している Independent/Isolated

テストが他のテストに影響を与えない

テストの実行順が
A->B
B->A
でも結果は同じ

高速にテストを実行する場合

テストの実行が速いと
テスト実行速度は開発効率に大きく影響します。

コードの動作確認が迅速にできる
問題発見が早くなり、修正に時間がかからない
コード変更への抵抗感が減り、開発効率が向上

低速なテストを実行の場合

テストの実行が遅いと
テスト実行頻度が下がり、問題発見が遅れる
問題修正に時間がかかり、開発効率が低下
コード変更への抵抗感が増し、開発意欲が低下

開発者テスト Developer Testing

コード変更による問題を早期に発見・修正

理想は無駄なく漏れなくテストコードを書くこと

テストカバレッジはあくまでも目安

頻繁に実行することで、コードが動かなくなったタイミングを知り、直ぐに修正にはいり、調査する範囲は狭められます。

高品質なソフトウェア開発を実現

テストを自動実行することで得られる効果

テスト自動実行は、開発効率とソフトウェア品質を向上させる効果的な手段

開発者のモチベーション向上

即時フィードバックで自信と安心感を得られる
自己効力感の向上により開発生産性が高まる

デバッグ時間の削減

回帰テストで直前の変更による欠陥を早期発見
デバッグにかかる時間を大幅に削減
欠陥混入率の低下による生産性向上

テスト対象の理解促進

テスト記述を通してコードの動きを深く理解
仕様のあいまいさや潜在的な欠陥に気づきやすい

設計改善のきっかけ

テストが書きにくい場合、設計に問題がある可能性
実装者自身が設計変更を行い、テストしやすい設計へ改善
責務明確、結合度低、凝集度高、決定的な動作を実現
設計上の問題を早期解決し、手戻りを減らす

その他

人為的ミスによるテスト漏れを防ぐ
テスト結果を記録・管理することで、品質向上に役立てる

テストを自動実行することでしばらくしてから発揮される効果

テスト自動実行は、長期的に開発効率、ソフトウェア品質、チームワークを向上させる

個人

記憶力・把握力の限界を補い、過去の動作を検証
詳細で生きたドキュメントとして機能
コードの理解を促進し、設計改善のきっかけになる

チーム

属人性を軽減し、コードの共有・レビューを容易に
開発プロセスに品質を組み込み、責任感を高める
テストカバレッジなどのメトリクスで進捗管理
結合・デプロイ・リリースの判断を支える
長期的なコスト削減
根拠ある自信を生み出し、継続的な改善を促進

自動テストの注意点

自動テストは多くのメリットがある一方で、いくつかの注意点も存在する。これらの注意点を理解した上で、効果的に自動テストを活用することが重要である。

学習コスト

テストコードの書き方を学ぶ必要がある
初期は開発速度が遅くなる

実装からの時間経過

テストを書く難易度が上がる
設計変更のコストが高くなる
現状追認のテストになりやすい

メンテナンスコスト

テストコードも変更の影響を受ける
リファクタリングが必要
構造的結合に注意

品質保証

欠陥を減らす効果がある
品質保証としてはもの足りない
第三者検証の観点が必要

その他

自動テストは万能ではない
状況に合わせて使い分ける

テストファーストとは

テストファーストは、ソフトウェア開発の品質と効率を向上させる効果的な手法です。
ただし、いくつかの注意点も存在するため、状況に合わせて使い分けることが重要です。

テストファーストとは

テストファーストとは、コードを実装する前にテストコードを先に書く開発手法です。

メリット

設計段階から品質を意識できます。
欠陥の早期発見・修正が可能
コードの保守性を向上
開発効率の向上

デメリット

テストコードを書くための学習コスト
設計変更の難易度
テストコードのメンテナンス

テストファーストの効果と注意点

テストファーストは、ソフトウェア開発の品質と効率を向上させる効果的な手法です。ただし、いくつかの注意点も存在するため、状況に合わせて使い分けることが重要です。

メリット

必ずテスト可能なコードになる
設計改善効果が高い
インターフェースと実装を分けて考えられる
利用者の視点に立った設計を導く
欠陥の早期発見・修正が可能
コードの保守性を向上
開発効率の向上

デメリット

設計しすぎのムダ(スコープクリープ)に注意
修正性(変更容易性)にはあまり関与しない

テスト駆動開発のメリット

TDDは、プログラミングを楽しく、誇らしいものにし、変化への適応と良い設計への道を開きます。

達成感と誇り

小さな挑戦と成功を繰り返すことでゲーム感覚で開発できる
リファクタリングにより常に美しいコードを維持
プログラマーとして常に誇りがもてます。

変化への適応

常に必要十分かつシンプルな設計を維持
身軽さを維持することで予想外の変化にも対応
リファクタリングで最適な設計へとスムーズに移行

良い設計への道

良い設計を導くというよりは、近づく準備を整える
フィードバックと改善のプロセスを組み込むことで答えに近づいていく


感想

個人の感想なので折りたたんでおきます。

ポエム:これからのテスト駆動開発の学習で望むこと

AIを利用したテスト駆動開発

テストは広範囲に広がっていて、開発には色々な種類のテストがある。
どこから入門すればいいのかわからない。

↑つまり、本を網羅的に読んで理解していくパターンは効率が悪い。

テスト駆動開発とWebアプリ、コンポーネント、Hooks、Next.js、Serve Actionのテストの関係が繋がらない。

有名なチュートリアル
例えばReactの◯☓ゲームをテスト駆動開発で解くとどうなるか?

有名なフレームワークを使ったテスト駆動開発のサンプルを作る。

初心者のための~
ゼロから始める~
などの簡単な入門書はない。(Amazon検索調べ)

現状はリポジトリについているテストを見たり、
すぐに時代遅れになるツールを使ってテストを書く参考書だったり
テスト駆動開発の素人から見たらまだまだ不満は多い。



参考

【翻訳】テスト駆動開発の定義 - t-wadaのブログ
https://t-wada.hatenablog.jp/entry/canon-tdd-by-kent-beck

保守しやすく変化に強いソフトウェアを支える柱 自動テストとテスト駆動開発、その全体像 ~Software Design 2022年3月号「そろそろはじめるテスト駆動開発」より | gihyo.jp
https://gihyo.jp/article/2024/01/automated-test-and-tdd

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0