ホームページ  >  記事  >  バックエンド開発  >  なぜ単体テストを行うのか?テストはどのように実施するのですか?

なぜ単体テストを行うのか?テストはどのように実施するのですか?

青灯夜游
青灯夜游転載
2022-10-10 19:19:392250ブラウズ

なぜ単体テストを行うのか?テストはどのように実施するのですか?

このトピックについて私が話しているビデオへのリンクがあります

このビデオが気に入らない場合は、ここをクリックしてください長いバージョンです。

ソフトウェア

ソフトウェアは変更可能です。これが「ソフトウェア」と呼ばれる理由であり、その可塑性はハードウェアよりも強いです。優れたエンジニアのチームは、ビジネスの成長に合わせて付加価値を高め続けるシステムを作成し、企業にとって素晴らしい資産となるはずです。

では、なぜ私たちはこれが苦手なのでしょうか?完全に失敗したプロジェクトを何件聞いたことがありますか?あるいは、「レガシー」になり、完全に書き直す必要があります (書き換えも通常は失敗します!)

ソフトウェア システムはどのようにして「失敗」するのでしょうか?正しくなる前に修正することはできないのでしょうか?これが私たちの約束です!

多くの人が Go でシステムを構築することを選択します。これは、Go をより読みやすくすることを期待して多くの選択が行われてきたためです。 [関連する推奨事項: Go ビデオ チュートリアル ]

  • 私のこれまでの Scala でのキャリアと比較すると、首を吊るしたくなる衝動に駆られると思います , Go には 25 個のキーワードと、標準ライブラリやその他の小さなライブラリから構築できる 多数のシステムしかありません。ビジョンは、Go を使用してコードを作成し、6 か月後に振り返ってもまだ意味があるということです。

  • テスト、ベンチマーク、セマンティック解析および読み込みのためのツールは、ほとんどの代替ツールと比較して一流です。
  • 素晴らしい標準ライブラリ。
  • 厳密なフィードバック ループによりコンパイルが非常に高速になります
  • Go は下位互換性への取り組みを行っています。将来的には Go にジェネリックスやその他の機能が追加されるようですが、設計者は 5 年前に書いた Go コードでもビルドできると約束しています。私はプロジェクトを Scala 2.8 から 2.10 にアップグレードするのに数週間を費やしました。
  • これらの優れた特性をすべて備えていても、依然として悪いシステムを作成する可能性があるため、使用する言語が優れているかどうかに関係なく、過去のソフトウェア エンジニアリングを振り返る必要があります。 . そして学んだ教訓を理解します。

1974 年、[マニー リーマン] (

https://en.wikipedia.org/wiki/Manny_Lehman...

) という名の賢いソフトウェア エンジニアが、ダウンロード Lehman Software Evolution を書きました。法###。 これらの法則は、新たな発展を推進する力と進歩を妨げる力の間のバランスを説明しています。

開発したシステムがレガシーになり、何度も書き直されることを望まない場合、これらの力を理解する必要があります。

#継続的変化の法則

実生活で使用されるソフトウェア システムは常に変化しなければなりません。そうしないと、一般的な環境によって排除されてしまいます

明らかに、システムは

継続的に変更する必要があります。そうしないと、ますます役に立たなくなってしまいます。しかし、この状況がしばしば無視されるのはなぜですか?

なぜなら、多くの開発チームが成果を上げることでボーナスを得るからです。指定された日付までにプロジェクトを完了すると、次のプロジェクトに進みます。ソフトウェアが「幸運」であれば、少なくともそれを維持するために別のグループに何らかの形で引き渡されるでしょうが、彼らがそれを反復し続けることは確実にありません。 人々は、システムの永続性開発に焦点を当てるのではなく、「迅速な提供」を支援するフレームワークの選択を心配することがよくあります。

あなたが優れたソフトウェア エンジニアであっても、システムの将来のニーズを理解していないと犠牲になる可能性があります。ビジネスが変化すると、あなたが書いた素晴らしいコードは意味がなくなる可能性があります。

リーマンが 1970 年代に大成功を収めたのは、熟考に値するもう 1 つのルールを彼が与えたからです。

複雑さ増大の法則

システムが発展するにつれて、システムの増大を軽減するための措置を講じない限り、システムの複雑さは増大し続けます。

彼が今言いたいのは、「システムが長時間稼働し続けるために、ソフトウェアにますます多くの機能を集中させるだけで、ソフトウェア チームを純粋な機能工場にすることはできない」ということです。長い間。

私たちの知識の状況が変化するにつれて、私たちはシステムの複雑さを引き続き管理しなければなりません。

リファクタリング

ソフトウェア開発では、次のような

多くの

側面でソフトウェアの可塑性を維持できます。 開発者権限

通常は「良好な」コードです。コードの適切な分離などに注意してください。

  • コミュニケーション能力

  • アーキテクチャ

  • 可観測性

  • #展開可能性
  • #自動テスト
  • #クローズドループ

  • リファクタリングに焦点を当てます。プログラミングの初日に開発者からよく聞かれるのが、「これをリファクタリングする必要がある」という言葉です。

  • この文は and から来ていますか?リファクタリングはコードを書くこととどう違うのですか?
  • 私や他の多くの人が 自分たちがリファクタリングしていると思っていたことはわかっていますが、それは間違っていました。

    Martin Fowler は、人がどのように間違いを犯すかを説明しています

    ただし、「リファクタリング」は不適切な場所でよく使用されます。誰かがリファクタリング中に数日間ダウンしたシステムについて話し合った場合、その人はリファクタリングしていないと確信できます。 #########それは何ですか?

    因数分解

    学校で数学を勉強したとき、おそらく因数分解について学んだでしょう。これは非常に簡単な例です。 Calculate

    1/2 1/4

    これを行うには、分母を因数分解します、式を # に変換します。

    ##2/4 1/4 これを 3/4

    .

    に変えることができます。ここからいくつかの重要な教訓を学ぶことができます。 式を分解する場合、式の意味は変更されません。どちらも

    3/4

    に等しいですが、1/22/4 に変更すると作業が容易になり、より「分野」に適したものになります。 コードをリファクタリングするときは、現在のシステム要件に「適合」させながら、コードを理解しやすくする方法を見つけるように努める必要があります。重要なのは、 コードの元の動作を変更しないことです。.

    Go の例

    次のメソッドは、特定の ## を使用します。 # language

    挨拶

    name
    func Hello(name, language string) string {
        if language == "es" {
            return "Hola, " + name
        }
    
        if language == "fr" {
    
            return "Bonjour, " + name
    
        }
    
        // 想象一下更多的语言
    
        return "Hello, " + name
    
    }

    if ステートメントが何十もあると不快に感じられ、特定の ## を繰り返し使用する必要があります # language は、, 挨拶

    name

    と一致します。それでは、コードをリファクタリングしましょう。 <pre class="brush:php;toolbar:false">func Hello(name, language string) string {       return fmt.Sprintf(           &quot;%s, %s&quot;,           greeting(language),           name,       ) } var greetings = map[string]string {   es: &quot;Hola&quot;,   fr: &quot;Bonjour&quot;,   //等等... } func greeting(language string) string {   greeting, exists := greetings[language]   if exists {      return greeting   }   return &quot;Hello&quot; }</pre>実際には、このリファクタリングの性質は重要ではありません。重要なのは、コードの動作を変更しなかったことです。 リファクタリングするときは、インターフェイス、新しい型、関数、メソッドなどを追加するなど、好きなことを行うことができます。唯一のルールは、コードの動作を変更できないことです。 コードをリファクタリングするときに機能を変更しないでくださいこれは非常に重要です。リファクタリング時に機能を変更すると、

    two

    のことを同時に行うことになります。ソフトウェア エンジニアとして、私たちはシステムをさまざまなファイル、パッケージ、関数などに分割する方法を学ぶ必要があります。なぜなら、何かの大きな部分を理解しようとするのは難しいことを知っているからです。

    一度に多くのことを考えるべきではありません。間違いを犯すことになるからです。私は、開発者が噛みつく以上に噛み砕いたために、多くのリファクタリング作業が失敗するのを目撃してきました。

    数学の授業で紙とペンを使って因数分解をしたとき、頭の中で式の意味が変わっていないか手動で確認する必要がありました。コードをリファクタリングするとき、特に重要なシステム上で、機能が変更されたかどうかをどうやって知ることができますか?

    テストを書かないことを選択した人は、多くの場合、手動テストに依存します。小規模なプロジェクトでない限り、これには膨大な時間がかかり、長期的には将来のシステムの拡張には役に立ちません。

    安全にリファクタリングするには、単体テストが必要です。

    これにより、機能の変更を気にせずにコードをリファクタリングできます

    開発者がシステムをどのように実行すべきかに関するドキュメントを作成するのに役立ちます

    # 手動テストよりも迅速で信頼性の高いフィードバック

    • Go の例

      次のような
    • Hello
    • メソッドの単体テストがあります。

      func TestHello(t *testing.T) {
      
          got := Hello("Chris", es)
      
          want := "Hola, Chris"
      
          if got != want {
      
              t.Errorf("got %q want %q", got, want)
      
          }
      
      }
      コマンド ラインで、
    • go test## を実行できます。 # そして、リファクタリング作業が元のプログラムの実行に影響を与えるかどうかについて、すぐにフィードバックを得ることができます。実際、エディタ/IDE でテストを実行する方法を学ぶ方が良いでしょう。
    • プログラムの実行ステータスを取得したいと考えています

    小規模なリファクタリング

    テストを実行します

    繰り返し

      すべてが非常に緊密なフィードバック ループに組み込まれているため、間違いを防ぐことができます。
    • すべての主要な動作が単体テストされ、1 秒以内にフィードバックが与えられるプロジェクトを用意することは、リファクタリングが必要なときに大胆な決定を下すことを可能にする非常に強力なセーフティ ネットです。これは、リーマン氏が説明する増大する複雑性を管理するのに役立ちます。

    • 単体テストは非常に優れていますが、それを作成するときに時々抵抗に直面するのはなぜですか?

    • 一方で、単体テストは自信を持ってリファクタリングを継続できるため、システムの長期的な健全性にとって重要であると言う人 (私と同じように) もいます。
    • 一方で、単体テストは実際には

      リファクタリングを妨げるという人もいます。
    リファクタリング時にテストをどれくらいの頻度で変更する必要があるかを自問してください。私は長年にわたり、テストカバレッジが非常に高い多くのプロジェクトに携わってきましたが、エンジニアはテストを変更するのは手間がかかると考え、リファクタリングに消極的でした。

    これは私たちの約束に反しています! #########どうしてこれなの?

    正方形を描くように求められたとします。これを行うための最良の方法は、2 つの三角形を接着することだと考えられます。

    2 つの直角三角形は正方形を作ります。

    正方形の周囲に単体テストを作成して、両辺が等しいことを確認してから、三角形の周囲にいくつかのテストを作成します。三角形が正しくレンダリングされていることを確認したいので、角度の合計が 180 度であると主張し、2 つのテストを実行して確認します。テスト カバレッジは非常に重要で、これらのテストの作成は非常に簡単なので、そうしない理由はありませんか?

    数週間後、法律の変更が私たちのシステムに影響を及ぼし、新しい開発者がいくつかの変更を加えました。彼女は今、2 つの三角形よりも 2 つの長方形から正方形を作る方が良いと考えています。

    2 つの長方形が正方形を形成します

    彼はこのリファクタリングを試し、いくつかの失敗したテストからいくつかのヒントを得ました。彼は本当にコードの重要な機能を壊したのでしょうか?彼女は今、これらの三角形のテストをさらに深く掘り下げて、内部で何が起こっているのかを正確に理解しようと努めなければなりません。

    正方形が三角形で構成されていることは実際には問題ではありませんしかし、私たちのテストでは実装の詳細の重要性を誤って高めてしまいました

    実装の詳細ではなくテスト機能

    単体テストについて人々が不満を言うのを聞くと、それは通常、テストの抽象化レベルが間違っていることが原因です。彼らは皆、実装の詳細をテストし、協力者のコードを執拗に観察し、そしてたくさんの嘲笑をしていました。

    この問題は、ユニットテストに対する誤解と、メトリクス (テストカバレッジ) の追求に起因すると思います。

    機能のテストだけについて話しているのであれば、システム/ブラック ボックス テストを作成するだけでよいのではないでしょうか?この種のテストは、主要なユーザー ジャーニーを検証する上で多くの価値がありますが、多くの場合、作成にコストがかかり、実行に時間がかかります。このため、フィードバック ループが遅いため、リファクタリングにはあまり役に立ちません。さらに、単体テストと比較すると、ブラック ボックス テストは根本的な問題の解決にはあまり役に立ちません。

    それでは、は正しい抽象化レベルでしょうか?

    効果的な単体テストを作成することは設計の問題です

    テストのことは少し忘れてください。自己完結型で分離された「ユニット」をシステムに含めたほうがよいでしょう、センターあなたの分野の重要な概念について。

    私は、これらのユニットを、他のブロックと組み合わせて大規模なシステムを構築できる、一貫した API を備えたシンプルなレゴ ブロックとして考えるのが好きです。これらの API 内には、必要に応じて連携して動作する多くのもの (型、関数など) が存在する場合があります。

    たとえば、Go を使用して銀行システムを開発する場合は、「アカウント」パッケージが必要です。実装の詳細が漏洩せず、統合が容易な API を提供します。

    ユニットがこれらのプロパティに従っている場合は、そのパブリック API に対する単体テストを作成できます。

    定義上、これらのテストは有用な機能のみをテストできます。これらのユニットを配置すると、必要なときにいつでも自由にリファクタリングでき、ほとんどの場合、テストが妨げられることはありません。

    これらは単体テストですか?

    はい

    。単体テストは、私が「ユニット」と表現するものに対するものです。 決して 1 つのクラス/関数などをターゲットにすることはありません。 #これらの概念の結合

    ##これについてはすでに説明しました

    ##リファクタリング

      #単体テスト
    • 単体設計
    • ソフトウェア設計のこれらの側面は相互に補完的であることがわかります。
    • リファクタリング

    単体テスト用のシグナルを提供します。手動で確認する必要がある場合は、さらにテストが必要になります。テストが失敗した場合、テストの抽象化レベルは間違っています (または、値がないため削除する必要があります)

      は、ユニット内およびユニット間の複雑さに対処するのに役立ちます。
    • 単体テスト

    リファクタリングの安全保護を提供します。

      ユニットの機能を検証し、文書化します。
    • (よく設計された) ユニット

    簡単に記述できる 意味のある ユニット テスト。

    • リファクタリングが簡単。

    • コードを継続的にリファクタリングして複雑さを管理し、システムのスケーラビリティを維持するのに役立つプロセスはありますか?
    • なぜテストドライブ開発 (TDD) を行うのか

    ソフトウェアを常に変更する方法に関するリーマンのアイデアのせいで、事前に「完璧な」スケーラブルなシステムを作成しようとして過度に設計し、多くの時間を無駄にする人もいるかもしれません。 。

    ソフトウェアの古き良き時代には、アナリストのチームが要件文書の作成に 6 か月、アーキテクトのチームが設計に 6 か月を費やし、数年後にはプロジェクト全体が失敗していました。 昔は悪かったと言いましたが、今もそうです!

    アジャイル開発は、フィードバックをすぐに得られるように、小規模から始めてソフトウェアを継続的に改善しながら、反復的に作業する必要があることを教えてくれます。ソフトウェアの設計とそれが実際のユーザーとどのように連携するかについて検討し、TDD はこのアプローチを強制します。

    TDD は、常にリファクタリングして反復的に提供する開発アプローチを奨励することで、リーマン氏が語る法則やその他の歴史的に学びにくい教訓に対処します。

    小さなステップ

    • 小さな関数の小さなテストを作成する

    • テストが有効かどうかを確認する失敗し、明らかなエラーがあります (赤)

    • テストに合格するための最小限のコードを作成します (緑)

    • リファクタリング

    • 上記の手順を繰り返します

    熟練度が上がるにつれて、これが自然な作業方法となり、作業効率も向上します。どんどんレベルが上がっていきます

    プログラムが非「グリーン」状態にあることがわかると、小さなテストユニットがテスト全体を完了するのにそれほど時間はかからないことを望み始めます。 , これは、ちょっとしたトラブルが発生した可能性があることを示しています。

    これらのテスト フィードバックを使用すると、いくつかの小規模なアプリケーション機能の安定性を簡単に確認できます。

    満足のいく結末

    • このソフトウェアの利点は、必要に応じて変更できることです。時間が経つにつれて、いくつかの予測不可能な理由により、ほとんどのソフトウェアはニーズに応じて対応する変更を加える必要がありますが、将来を予測するのは非常に難しいため、最初から無理をしたり過度に設計したりしないでください。

    • したがって、上記のニーズを満たすためには、ソフトウェアのスケーラビリティを維持する必要があります。そうしないと、ソフトウェアのリファクタリングとアップグレードが必要になったときに状況が非常に悪くなります。

    • #優れた単体テストは、プロジェクトを迅速かつ楽しくリファクタリングするのに役立ちます。

    • 優れた単体テストを書くことは設計上の問題です。各単体テストがレゴ ブロックを組み立てるのと同じくらい興味深いものになるように、コードの構造を慎重に検討する必要があります。 は正常に完了しました。プロジェクト全体のテスト。

    • テスト駆動開発 (TDD) は、適切に設計されたソフトウェアを反復的に開発するのに役立ち、これをテクニカル サポートとして使用すると、今後の作業に大きな影響を与えます。 。

    元のアドレス: https://quii.gitbook.io/learn-go-with-tests/meta/why

    翻訳アドレス: https: //learnku.com/go/t/34095

    プログラミング関連の知識については、

    プログラミング ビデオをご覧ください。 !

以上がなぜ単体テストを行うのか?テストはどのように実施するのですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。