Web APIを簡易にe2eテストしたい:技術選び編


※この記事での e2e はフロントエンドを含みません。

学ぶ対象とテストについて

触ったことがないプログラム言語やフレームワークを触るとき、ユニットテストはそのプログラミム言語やフレームワークの流儀に従うのが良いと考えています。流儀に沿ってユニットテストを書くことは学びたい対象の学びになることが多く、効果的に思います。

一方、e2e レイヤーのテストは学びたい対象の流儀に合わせるものではないと考えています。例えば、特定のエンドポイントにアクセスしたらあるステータスコードとレスポンスが返ってきて、DB に値が入っているという状況をアサートするテストは、テスト対象がどのプログラム、フレームワークで書いてあるかは関係なくテストできるべきと考えているからです。API が Rust で作られているか、Go で作られているかはこのレイヤーにおいて関係ないはずです。

そのため、あるプログラム言語やフレームワークを学ぶという観点だと、 e2e レイヤーのテストを書くのは学びの意味が変わってくるような気がしていたわけなのですが、一方で学ぶ対象と関係なく e2e テスト書いた方が便利なのではと思うことも増えました。

モチベーション:E2E テストが通ったら OK とできる

触ったことがないプログラム言語やフレームワークの場合、慣れていないので色々改良しているうちに壊したり、意図した形でレスポンスを返せていないことが多々あります。

こういったことを人力で細かく確認するのは大変で、とくに認証付きルートの場合は認証部分も含めて curl して確認!とするのはシンプルに面倒です。そういった部分は E2E テストで機械的にテストした方が E2E 書く時間はあるにしろ、総合的に時間かからないのでは?と思ったのが今回のモチベーションです。

E2E テスト実装コストを小さくしたい

E2E テストにはさまざまな手法や、便利なフレームワークがあり、どのように E2E テストを書くか考えるかだけでいくらでも時間潰せそうです。今回の E2E の目的は、学習対象の Web API の動作確認コストを下げることです。条件としては下記を満たしたいです。

  • 特定プラットフォームに縛られないこと
  • E2E 用のフレームワークを使う場合、(自分的に)学習コストや環境構築コストが低いこと
  • E2E 環境の保守やアップデートは可能な限り避けられる、あるいは簡単なこと
  • E2E を書くプログラム言語もできれば今興味あるものが良い

検討したもの

テストコードを簡易にしたいので便利なフレームワークを使った方が良いのかなと思いながら探しました。趣味で使うものなので、多機能さだけでなく自分が飽きなさそうというのも大切な要素です。

Tavern - Python

上記の条件で色々検討したところ、Python の Tavern が第一候補となりました。Python の本を読んでいた時期ということもあり、Python 熱が高かったのも選定ポイントの 1 つ。

Tavern

必要なアサートや設定を簡易にできること、フレームワーク自体軽量そうということもあって目的に合致していました。

ただ、いくつかテスト書くうちに yaml ファイルにテスト内容を書いて実行する形がどうしても気になりました。フレームワークを利用する以上、固有のルールは避けられないことなので Tavern ではなく Python 直接の実装の方が良い?と試行錯誤したもののいまいちハマらず。凄く便利そうだけど趣味としてどうかという点で保留に。

Pact

フレームワークを利用するなら、CDC テストチャレンジはどうだろと思いました。

https://github.com/pact-foundation

検討はしたものの、当初の目的と明らかに外れるのでこれは CDC の学びをする際に使ってみることにしました。

Go

実用 Go 言語を読んでいて、これだ!となりました。Go が持つテストの機能と、net/http ライブラリを利用する形で、API テスト用フレームワーク使わない通常の Go のテスト構成です。

API テスト用フレームワークと比較して、テストコードの量は増えそうではあります。ただ、特定のフレームワークに沿った実装にはならないため、E2E テストを書くことで Go のテストが上手くなると考えると汎用性があってモチベーションに繋がりそうなところ、長期的に見ても Go 言語自体のキャッチアップをしたら継続できそうなところは魅力的に思いました。

多機能なフレームワークを触ってみたり、仕事で使っているものも検討はしたものの、個人用途だと言語自体の機能を使う方が肌に合っているのかなと思ったりでした。ということで、Go でテストを書くことにしました。

テスト用環境の想定

Web API を作るときは DB と認証用のサービス(Auth0)を大抵くっつけています。e2e テストでは DB は本物を使い、認証サーバーはモックすることにしました。メールサーバーなど他に必要なものが出てきたら都度増やします。

環境

CI のことはひとまず置いといて、ローカルの kubernetes に環境を構築してテストする想定です。API は JWT 認証を想定しており、JWT の発行は E2E の部分で行ってアクセス時に header につけます。Auth0 の Mock から配信する JWKS と遂になる秘密鍵を、 E2E のテスト環境が持っている形です。JWT を発行する Mock を 1 個たてて取得する方が良いのかもしれませんが、API からすると JWT の取得は依存関係にないので発行の Mock は立てていません。E2E は DB に直接アクセスし、テスト実行前にデータのセットアップを行います。

ひとまずこんな構成で作れば自分的には満足なものとなりそうです。ローカルで安定してきたら CI での実行を考えてみようと思います。k8s をどこに立てるかなんですよねえ。。。