Go でのテスト駆動 API 開発

王林
リリース: 2024-07-18 01:18:11
オリジナル
530 人が閲覧しました

Test-driven API Development in Go

導入

テスト駆動開発は、十分にテストされ、リファクタリング可能なコードを確保するための効果的な方法です。基本的な考え方は、テストを書くことから開発を始めるということです。これらのテストは期待値を明確に文書化し、実装を成功させるためのルーブリックを作成します。適切に実行すると、コードを記述する前に関数の予想される入出力を明確に定義できます。これにはすぐにいくつかの利点があります:

  • コードを操作するためのインターフェイスを慎重に検討し、テストしやすいように設計します
  • コードの作成を開始しても、手動テストや結果を予測するための実行ロジックのステップ実行によってフローが中断されることはありません。代わりに、テストを実行するだけです
  • テストに合格することは、達成することで満足のいく目標になります。プロセスを明確に定義された達成可能な一連のマイルストーンに分割すると、作業がより楽しくなります
  • コードのテストを妨げる可能性のある実装後の怠惰や自信過剰を避けてください

メリットを理解したら、次の手順に従ってテスト駆動開発 (TDD) を開始できます。

  1. テストを作成または変更する
  2. テストが失敗したかどうかを確認します
  3. テストに合格するために最小限のコードを記述します

これらの手順はサイクルで実行されるため、常にテストを追加して現在の実装に挑戦することになります。

最後のステップでは、最小限のコードを記述することが指定されていますが、厳密に従うと作業が退屈になる可能性があります。いつルールから逸脱するのが適切かを判断する前に、このルールが存在する理由を理解することが重要です。

簡単な例

あなたには関数 Add(x, y int) int を実装するという使命があります。実装に進んで x + y を返す前に、最も単純なテスト 1 + 1 == 2 を作成します。それでは、テストに合格する最も単純な実装は何でしょうか?リターン 2 です。これでテストは成功しました!

この時点で、さらにテストが必要であることがわかり、ペースを上げてさらにテストをいくつか追加します。

  • 1 + 2 == 3
  • 100 + 5 == 105

今度はテストが失敗するので、実装を修正する必要があります。今回は単に 3 を返すことも 105 を返すこともできないため、すべてのテストに有効な解決策を見つける必要があります。これにより、return x + y.

という実装が行われます。

この単純な例では非常に面倒に感じますが、この方法を厳密に遵守すると、実装を信頼するだけでなく複数のテストを作成することになります。もちろん、x + y を返すという最初のアイデアは機能したでしょうが、重要なのは、コードに対する自分自身の理解ではなく、テストに依存するように自分自身を再訓練することです。現実の世界では、このコード部分に取り組んでいるのはあなただけではないため、必然的に実装の詳細を忘れてしまいます。このプロセスでは、より多くのテストを作成し、単純な実装を壊すためのより多くの方法を考える必要があります。

最終的には経験を積み、遭遇するさまざまなシナリオで機能するバランスを見つけることを学びます。機能のフルスピード実装に戻り、バグが減り、より保守しやすいコードを作成できることがわかります。

HTTP API の段階的な TDD

HTTP REST API に TDD を使用した、より複雑な例を見てみましょう。このステップバイステップのガイドでは、私の Go フレームワーク、babyapi を使用していますが、この概念はどこにでも適用できます。

babyapi はジェネリックスを使用して Go 構造体を中心とした完全な CRUD API を作成し、完全な REST API とクライアント CLI を非常に簡単に作成できるようにします。これに加えて、babytest パッケージは、エンドツーエンドの API テーブル テストを作成するためのいくつかのツールを提供します。 API レベルで TDD を使用すると、新しい API または機能の HTTP 層とストレージ層を一度に完全にテストできます。

免責事項: babyapi は実装の大部分を処理し、テスト定型文の生成にも使用されるため、技術的には TDD から始めているわけではありません。ただし、API に PATCH リクエストのサポートを追加すると、それがどれほど有益であるかがわかります。

  1. 新しい Go プロジェクトを作成する


  2. babyapi の簡単な例を使用して初期の main.go を作成します


  3. CLI を使用してテストボイラープレートを生成します

  4. プレースホルダーに予想される JSON を入力して各テストを実装します
  5. テストを実行して、テストが成功することを確認してください。

    PUT は冪等であるため、すべてのフィールドを含める必要があります。これを回避するために、PATCH リクエストで完了を切り替えるサポートを追加したいと考えています。まず、この機能がどのようになるかを予想するための簡単なテストを追加します
  6. This test fails since babyapi doesn't support PATCH by default. We can fix it by implementing Patch for the TODO struct. Since we defined our feature with two tests, our simplest implementation isn't just setting Completed = true and we have to use the value from the request

  7. Now we can change the Completed status of a TODO, but we still cannot use PATCH to modify other fields as show by this new set of tests

  8. Update Patch to set the remaining fields

  9. Our tests still fail since we always update the TODO with the request fields, even if they're empty. Fix this by updating the implementation to check for empty values

  10. The new UpdateWithPatch test passes, but our previous tests fail. Since we changed Completed to be *bool, TODOs created with an empty value will show as null

  11. Implement Render for TODO so we can treat nil as false

Implementing the PATCH feature with test-driven development resulted in a robust set of tests and a well-implemented feature. Since we started by defining the expected input and output of a PATCH request in tests, it was easy to see the issues caused by not checking for empty values in the request. Also, our pre-existing tests were able to protect from breaking changes when changing the type of Completed to *bool.

Conclusion

Test-driven development is an effective approach for creating fully tested and correct code. By starting with tests in mind, we can ensure that every piece of code is designed to be testable instead of letting tests be an afterthought.

If you're hesitant about adopting TDD, here are a few ideas to get started:

  • Try it in simple scenarios where a function's input/output is clear and the implementation is not overly complicated. You can write a robust table test for the variety of input/output that could be encountered. Having a clear visual of the different scenarios can simplify implementation
  • If you're fixing a new bug, you have already identified a gap in your testing. Start by writing a test that would have identified this bug in the first place. Then, make this test pass without breaking any existing tests.
  • Similar to the babyapi example, you can use TDD for high-level API tests. Once you have a definition of the expected request/response, you can resume your usual development flow for more detail-oriented parts of the implementation

Even if TDD isn't a good fit for the way you write code, it's still a powerful tool to have in your belt. I encourage you to at least commit some time to trying it out and see how it affects your development process.

以上がGo でのテスト駆動 API 開発の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!