既存システムのテスト自動化を考える
はじめに
皆さんこんにちは!オプスイン開発エンジニアの新川です。
最近、他社さんより引き継いだシステムを継続開発する中で、品質を担保するためにテスト自動化への取り組みを進めています。
本記事では、テスト自動化とは何なのか、何のために、どのような方法で行うのか、さらに、既存機能のテストを自動化する上でどのように行うか、検討した内容などをご紹介したいと思います。
テスト自動化とは?
Wikipediaでは、以下のように記載されています。
テスト自動化(テストじどうか)とは、テスト支援ツール等を使うことにより、ソフトウェアテストを自動化することである。
「テスト支援ツール」って何?と思う方もいらっしゃるかもしれません。
テスト支援ツールはテスト対象やスコープに応じて様々にカテゴライズされると思いますが、皆様に身近なもので言うと、最近のWeb開発フレームワークには大抵このテストツールが標準で備わっているか、あるいはパッケージ追加で利用可能にできるケースが多いと思います。
弊社ではRuby on Railsで開発を行う場面が多いですが、Railsのチュートリアル本家でも標準搭載のMinitestを用いたテスト方法が紹介されています。こうしたWebフレームワーク用のテストを実行する際は、コマンドライン上でテスト用のコマンドを実行するだけで、自動でテスト用データベースを自動作成し、テストが行われ、結果が得られます。Minitestでもそうですが、テストツールを用いてテストを自動化する場合、ソースコードとは別にテストコードを別途作成し、同じプロジェクト内にコミットするのが基本です。これにより、開発者が開発後に手軽にテストを走らせることができます。
テスト自動化のメリット
「テストコードを別途書くのって、開発工数上がるんじゃない?」と思う方もいらっしゃるかもしれませんが、その通りだと思います。しかも、フレームワークの実装方法が分かっていればすぐテストが書けるというものでもなく、テストコードはテストコード専用の知識が必要だったりして、学習コストも上がります。
ただ、私はテスト自動化を進めることで、結果的に多くの場面で開発コストダウンと品質アップに繋がるんじゃないかと考えています。
この辺りは散々、他の記事でも紹介されていることですが、以下のようなものが個人的に思う主なメリットです。
テスト工数の削減になる
自動でテストした部分は品質が担保されているので、テスターが改めて手動でテストを行う必要がありません。開発時点でテストを何度も回すわけなので、実装完了時点での品質も上がり、テスト後の修正工数も下がるはずです。
ただ個人的には、新規に開発した部分に限り、自動テスト任せにするのではなく、全ての機能についてテスターによるテスト(目視の確認)も必要だと思います。
開発後のデグレに気付ける
「全然関係ない機能を開発していたところ、意図しない形で既存機能に不具合をもたらしてしまった」と言う経験、皆さんお持ちだと思います。
テスト自動化は毎回全てのテストを回すのが基本ですので、構築時点でテストを書いておけば、意図した通りに動作しなくなった時点ですぐに気づくことができます。
このため、開発段階で不具合に気づくことができ、修正をかけられます。また、テスターが追加開発ごとに全ての既存機能について詳細に動作をテストする必要がなくなります。
テストコードが仕様書になる
個人的には意外と重要な効果だと思うんですが、整理整頓して記載されたテストコードがあれば、読むだけで「そのシステムにどんな機能があるのか」が詳細に把握できます。
このため、詳細なドキュメントがなくても、引き継いだ人がテストコードを読むだけでシステムの中身を十分把握できるという効果ももたらされるように思います。
「仕様書?なにそれおいしいの?」という状態のプロジェクトも世の中にはたくさんあると思いますが、テストコードをしっかり書くことで、引き継がれた人にも優しいシステムになるのではないでしょうか。
テスト自動化のスコープ
これは個人的な主観も入りますが、ウェブシステムを例にとると、テスト自動化のスコープは大きく二つあると思います。
サーバサイドのテスト自動化
RailsのMinitestなど、バックエンドフレームワークのテストツールで自動化する範囲がここに当たります。
サーバサイドのため、モデルのバリデーション、POSTデータの受け渡しなどがメインのテストスコープになるかと思います。フロントエンド側でReactなど別のフレームワークを用いている場合などは、フロントエンド側はスコープ外となります。
利点として、フレームワーク側の言語を使ってテストコードを記述できるので、新たに言語を学習する必要がありません。また、ORMによるデータ操作もそのまま利用できますので、モデルに実装したカスタムメソッドなどもそのまま利用できます。また、テスト用のデータベースの作成や、テスト後のクリーンアップを自動でやってくれる機能が、テストツールに大抵備わっていますので、そうした機能を有効活用できます。
エンドツーエンドのテスト自動化
クライアント操作を自動化して行うテストです。ブラウザであれば、Puppeteer、Seleniumなどが利用されます。
フロントエンドも含めた一気通貫のテストですので、実際のユーザの操作と同じ環境でテストを行うことができます。
利点としては、ユーザの操作をほぼ完全に再現できるので、「フロントエンド側のUIコンポーネントが表示されていない」といった不具合にも気づくことができます。また、とりあえずエンドツーエンドでテストが通ったケースについてはサーバサイド側もOKと考えることもできるので、一石二鳥です。さらに、テスト自体は極端な話別プロジェクトにしてもいいくらいに疎結合にできるので、既存のシステムに影響を与えません。
難点として、クライアント操作自動化のための別言語を学習するコストがかかることや、データベースの生成やクリーンアップは手動で行わなくてはならないことなどが挙げられます。
既存システムのテストを自動化する
他社さん、もしくは社内の別担当者から開発を引き継ぐような経験、みなさんお持ちだと思います。
引き継がれた時点でテストがしっかり実装され運用が確立されている場合は万々歳ですが、私はこれまでそんな経験は一度としてありません。(泣)
こうしたシステムを継続的に開発していくにあたり、後追いでテスト自動化を実現する方法について検討しました。
結論から言うと、小規模なシステムであれば、クライアント自動化を用いたエンドツーエンドのスコープで自動化する方が良いと思います。
両スコープの実装を比較し、この結論に至った経緯をご説明します。
既存システムのサーバサイドテスト自動化について
引き継いだシステムでテスト自動化の運用が確立されていない場合、後追いでサーバサイドのテスト自動化を実装するのは結構難易度が高いように思います。
例えば、そもそもテスト環境でサーバを立ち上げる運用になっていない場合、テストサーバを立ち上げるためのコンフィグレーションの追加が必要だったり、場合によってはFixtureなどのダミーデータも用意する必要が出てきます。現行のシステムからデータを引っ張ってきて投入して、さらにそのDB生成やクリーンアップができるようにして…と意外にやることが多くなります。私の担当したシステムでは、Fixtureから投入したデータをSELECTしようとしても、どうしても取得することができませんでした。
その上、パッケージ追加等で既存のシステムに影響が出る可能性がないとは言い切れません。バージョンアップをサボっているシステムだと、テスト用のパッケージすら入らなかったり…。
このように、超えなければならないハードルが意外に多くなりがちではないかと思います。
既存システムのエンドツーエンドテスト自動化について
対して、エンドツーエンドで既存システムにテスト自動化を実装する場合、ディレクトリを分割して完全に疎結合の状態で実装できるので、既存システムへの影響を気にする必要がありません。
開発サーバを立ち上げた状態でテストを実行するだけで実現できますので、ローカルで開発している環境でそのままテストを走らせることができます。開発サーバさえ動作していれば、そのままテストを導入できるわけです。
無論、学習コストやDBクリーンアップの手段を考えるコストは出てきますが、それを鑑みてもサーバサイドでのテスト自動化を実装するよりコストは下がるのではないかと思います。
完全に疎結合ですので、既存部分に構わず最新のテストフレームワークを使うことができるのも大きなメリットです。(開発者としては一番嬉しいかもしれません。笑)
テストサーバ立ち上げやDBクリーンアップなどは、手順が確立してくれば npm run のスクリプトを用いて自動化することも可能です。私はコマンドラインでDROP DBして、SQLdumpや別途バックアップ用のDBからリストアするような手順でテスト後のクリーンアップを実現しました。(無理矢理感半端ないですが…笑)
おわりに
既存システムを自動化するにあたり、検討したことをご紹介させて頂きました。
勿論、ケースバイケースではあると思いますが、多くの場合でエンドツーエンドのテスト自動化がよりコスパが良いのではないか、と思います。
あまりテストのためのコストをかけられない小規模な事業でこそ、自動化による恩恵をより受けられるのではないでしょうか。また、テストは短調で退屈な作業ですが、自動化は開発力を活かせるので、書いていて結構楽しいものです。
近年のJavaScriptテスト界隈では、Jest, Puppeteer, Cypressといったキーワードが盛り上がっているみたいです。一昔前はSeleniumと言われていたのですが、時代の移り変わりは早いですね。
時代に取り残されないよう、今後もしっかりキャッチアップしていきたいと思います。
Author Profile
-
東京都のwebアプリ、スマートフォンアプリ開発会社、オプスインのメディア編集部です。
・これまで大手企業様からスタートアップ企業様の新規事業開発に従事
・経験豊富な優秀なエンジニアが多く在籍
・強みはサービス開発(初期開発からリリース、グロースフェーズを経て、バイアウトするところまで支援実績有り)
これまでの開発の知見を元に、多くのサービスが成功するように、記事を発信して参ります。