DevOpsに一番大切な「戦略」と「戦術」

小井土亨氏(以下、小井土):よろしくお願いします。小井土と申します。

少しだけ自己紹介します。プログラマーとして、たぶんみなさんが生まれる前からプログラムをやっていて、1980年って何年前だっていう話ですが。パッケージの開発をしています。その中で何やっているかっていうと、開発のガイドラインや、プロセス、ソフトウェアのアーキテクチャ、フレームワーク、自動化のテストを作っています。

自動化ももう長いことやっているのですが、今回はその自動化を作ってくうえでみなさんに紹介できるようにちょっとリファインしたので、直接の具体例っていうよりは、少し教育用にリファインしていると思います。

テストのパッケージ売っているわけではなくて、弊社は業務パッケージ売っているので、今回は特にツールの話はしませんが、基本的にはSeleniumとかで実際に実現している内容です。

コミュニティとしては、「テスト自動化研究会」と「SQiP」というものです。「XPJUG」は、XP祭りをやっていて、このあたりのコミュニティをやっていて、時々しゃべったりしています。仕事は本当にプログラマーで、日々プログラミングをしています。

DevOpsの戦略っていうと、テストの話と自動テストとアーキテクチャと、システムテストの自動アーキテクチャと3つありますが、たぶん一番下のところは軽く流します。

みなさんも話を聞いてるだけではなかなかおもしろくないと思うので、演習のテキストを用意してきました。そちらをメインに進めたいと思っています。

戦略、DevOpsはどういうもの? という話です。一番大切なのは、作業の流れをいかにスムーズに流すかだと思っています。それを実現するために、まず大切なのが戦略を立てて戦術と手法を使うことです。

戦略は、長期的な計画なのであまり具体性はありません。例えばテーマーパークだと「100万人にしよう」みたいな、そういう話です。戦術は「ファミリー向けのエリアを作りましょう」みたいな、具体的な方法ですね。ファミリー層をまず獲得しましょうと戦略立てて、目標が100万人。「ファミリー層を獲得する」のが戦略で、戦術が「ファミリー向けのエリアを作ろう」です。それで、具体的な方法として「パスポートを作ろう」みたいなかたちで考えなきゃいけません。

実際には、DevOpsでも、気をつけながらこういったかたちで戦略とか戦術とかをしっかり立てていかないと、作業が目的になってしまうことがあるんですね。要するに、目的を失ってしまうことがあるので、そこをなくさないためにも、しっかりとみんなで共有しようという話です。

短くするためにどんな方法があるかっていうと、一般的には2つのやり方があります。「早くやる」と「思い切って同期を非同期にしてしまう」。一緒にやっちゃうっていう作戦ですね。戦術は、この2つのやり方があると思います。

一般的に、どちらかというとこのスムーズに流すほうで速度を上げるという話があるのですが、さらにちょっと進めて、一緒にやってしまう、要するに並列化して順番にやらないというかたちですね。これがちょっと1つ、方法としてはおもしろいかなと思います。今日はこれをやるための話を進めていきたいと思います。

DevOpsをやる時に、問題がいくつか起こるわけですが、よく聞くのはシステムテストのテストコストが増えてしまうという話です。やはりどうしても、くるくる回すとテストをいっぱいやりたくなるので、テストがどうしても増えてしまいます。

Wモデルみたいなかたちでもありますが、結局テストが後ろに来ると、期間が短くなってしまうので、短い期間でいくらがんばろうとしてもツライというのがあります。

もう1つは、品質が悪くてバグが出るって話です。バグは出ると、管理をしなきゃいけないし、修繕しなきゃいけないし、レビューしなきゃいけないし、再発防止しなきゃいけないし、すごく大変です。このあたりをやるために、テストがあります。

システムテストを非同期化する「キーワード駆動テスト」

最近のDevOpsのテストだと、3つのテストをやりましょうという話がよくあります。システムテスト、結合テスト、単体テストで、今日はこの中のシステムテストの話をします。

ただ、システムテストをやるからといって単体テストをやらないのは非常に間違っています。やはり単体テストはしっかりやる。なぜかというと、単体テストはフィードバックが非常に早い。ただ、ユーザー視点ではないので、バランスをすごく考えてもらいたいと思います。ただ今日は、システムテストの話をします。

システムテストでは、やはり全体が正しく動くことを確認しなきゃいけないですよね。当たり前の話です。システムテストは、Wモデルでいうと一般的にはかなり後ろのほうですよね。ただ、これは実際には仕様化と対応づけられるので、すごくがんばれば仕様の段階からシステムテストの作業が開始できると私は考えています。そこからやることで、このWモデルの流れるのと並行して、システムテストの作業を進められるのではないかというのが今日の私の話です。

当然システムテストを自動化するわけですが、単に自動化するだけで先ほどの並列ができるという話ではなくて、一般的なシステムテストって、やはりシステムができてからテストする人が多いですね。

例えばツールを使ったりして自動化するような場合は、動くシステムがないとツールがキャプチャできないとか、いろいろなことがあるので、単なるキャプチャのシステムテストの自動化だと、どうしても並列まではいかないっていうのがあると思います。

それが無駄だと言っているわけではありません。それでも、十分繰り返しテストには使えるし、いろいろと使えるのですが、違うやり方もあるので、今日はそれを紹介します。ぜひ「そんなやり方もあるのだな」と理解してもらえればうれしいと思います。

システムテストと自動テストは、実際には兄弟みたいな感じです。自動テストはシステム側と写像みたいなかたちなので、システムテストをしっかり自動化するためには、システム側もテストに協力しなきゃいけません。

私はシステム側も作るし、システムテスト側も作るプロジェクトにいるので、非常にやりやすくてうまくいっているのですが、ぜひみなさんも「自動テストはシステムは関係ないんだよ」とか「それはなんかテストチームの役割だよ」とか言うのではなくて、チーム全体としてこういったことを進めるのが、やはり成功の一番の近道だと私は思っています。

やり方として1つ、キーワード駆動テストの話を今日はします。なぜキーワード駆動テストをやるかというと、先ほどの「システムテストを非同期化する」ということですね。要するに、Wモデルの仕様が決まった段階から、できればシステムテストの準備を進めて、早い段階から並行してやっていって、システムができたら速攻テストを流します。システムができてからテストケースを作るのはけっこうツライです。

テストができた頃には、システムをリリースしなければいけなくなってしまいます。次の時は使えるかもしれませんが、最初では使えないので、そういうことがないようにしましょう、というのが今日の話です。

じゃあキーワード駆動は何かって話ですが、「論理的なキーワードでテストケースを書くということ」です。ブラウザーでいうと、IDを使ってテストを書くのは非常に論理的じゃないんですね。意味のある言葉でテストを書きましょうということです。

具体的には、例えば「単価」に200を入れて「個数」に5を入れて「計算」を実行したら、「金額」が1,000ってカンマ付きで表示されて、それを確認するテストケースを、私は最近Markdownとテキストケースで書いています。昔はExcelも使っていたのですが、Markdownのほうが処理が速いので、最近はMarkdownを使っています。

テストに関係ない人間がわかるようなところもMarkdownに書いておいて、実際にはテストシナリオとテストケースを合体させたような、ドキュメントとしても使えるテストケースを最近では作っています。

ちょっとここで1回まとめます。実現するために戦略を立てますよ。それで、きちんと戦略に合わせてやりましょう。実際にキーワードを使ってみたらどうですかと言っています。

なんでキーワードが大事かというと、論理的だからです。仕様が決まった時点で、ある程度テストケースに対するなんらかの作業ができます。テストケースが書けるとは限らないのですが、キーワードを洗い出したり、どんなテスト書いたらいいんだろうと考えたりできます。自動テストのスクリプトとしてキックできるようにするといいのではないかという話です。

2種類の電卓に共通して使えるテストケース

ここから演習に入ります。今時間が15分経っています。いつもは2時間でやっている演習を15分でやるという(笑)。

まずWebの電卓があります。キーワード駆動は簡単です。どんなWebの電卓をテストしなきゃいけないか。これは今回こういう状況になっているって話ですね。

1つは、電卓といわれている「1+2×10」ってやると、30になるタイプですね。頭から計算するようなやつです。「iPhone」はこんな顔をしているのに、実際には21になって、ちょっとびっくりしました。21になるのが普通なのかなって思ったんですが、CASIOの電卓はきちんと30になります。

下に、数字的なやつを意識してくれる電卓があります。なんでこんな演習をするかっていうと、この2つで共通で使えるテストケースを考えましょうということなんですね。かなり論理的に書かないと、ぜんぜん違う仕様のものに対して同じテストケースを使うのは難しいです。

この2つができれば、次に違うものが来ても再利用が非常にしやすくなるので、すごく意味があります。

両方こんなテストを作んなきゃいけないかと言われると、そうはならないことが多いのですが、これは演習なので。こういうかたちで、どんどんいろいろな電卓をテストしなきゃいけない。毎回それごとに作っていたらすごく大変だから、共通部分は共通で作りましょう。それにキーワード駆動を採用するという演習です。

キーワードの書き方ですが、キーワードと対象ですね。引数とコメント。コメントは人間がわかるように書くもので、テストの実行にはかかわりがありません。なんでコメントがあるかというと、実際、テスト動かすとだいたい失敗するわけで、どこで失敗したとかがわかりづらくなっちゃうので、ログとか、そういったものに対してトレーサビリティを付けるためにコメントを用意しています。

いつもですね、キーワードの定義もみなさんにやってもらうのですが、時間の問題で今回は私が作ってきました。操作のキーワードは、一般的に操作と判定の2つがあればだいたい事足りることが多いです。

今回は全部クリアして、なにもなかったことにするという「オールクリア」のキーワードを用意しました。対象もありません。この電卓に対して、全部クリアしてくださいっていうキーワードです。

次にボタン操作です。ここはIDじゃなくてボタン名ですね。いわゆる電卓の、よく電卓に出てくる「1」とか「2」とかの数字ですね、あるいは「=」とか「×」とか、そういったものをキーワードの対象にします。

IDを対象にしてしまうと、特定のWebでしか使えないものになってしまいますが、リアルな電卓にあるものを使うことで、他のシステムでも利用できるようになります。それで、表示の確認をします。表示の確認はフォーマットされた文字列を確認をします。

テストケースは、こんなかたちで表形式で書いています。コメントは今回は省いてますが、ここは自由に書きましょう。まずオールクリアします。それで、ボタン操作で「1」、「+」、「2」って押して「=」を押すと、「3」になるよねっていうテストです。

これだと、先ほどの対象のシステムどちらでも大丈夫ですね。どっちでも「3」になるはずです。この2つで使えるテストケースが書けました。

ここまではいいのですけど、次ですね。0の割り算。だいたい0が割り算すると何か起きるんですね。これをちょっと考えてみましょう。

エラーのキーワードを定義してみてください。今回すごく重要なのは、2つのシステムで共通のやつを使えなきゃいけないので、そういうかたちでここのキーワードを作る必要があるということです。

0割りするとだいたいなんかが出るんですよ。電卓として0割りはよくあるので、ちょっとテストケースを書きたいと思います。そのテストケースをすべての、できればWebシステム、Web電卓で使いたい、ということで、「操作」と「オールクリア」と「確認」の3つだけではエラーが出たかどうかをチェックできないので、新しいキーワードを考えてみましょうという問題です。

その時何を考慮したかを考えてみましょう。できればそれを使って、キーワードのテストケースを書いてみましょう。

ちょっとここで補足なのですが、キーワードの粒度があります。論理的とはいっても、細かくも書けますし、ざっくりも書けるので、簡単に書けるっていうのと自由に書けるっていうのは、実際にトレードオフなのですね。

キーワード駆動を作った場合に、テストケースをいろいろな人に書いてほしいと思うのですが、そのときに簡単に書けるようにしたいって思うのですが、そうすると自由度が下がってしまいます。簡単というのは自由が低いということなのです。簡単なほうは論理性が高くて、自由なので具体性が高くなるのですね。なのでここのバランスが非常に大事です。

ただ、どちらかだけにするっていうやり方もありますし、両方作ってしまうやり方もあります。誰でも書けるようなテストケースの領域と、自由に書けるところを2つ分けて、ある程度細かくも書けるし、ざっくりも書けるやり方をするという手もあります。

ただ、両方を同じテストケースに書いてしまうと、動いたり動かなかったりするので、粒度の大きいものは大きいものだけでテストケースを書くとか、細かいほうは細かいだけとか、細かいほうは両方使ってもいいと思いますが、そういうルールを決める必要はあると思います。

私なんかは、このキーワードもけっこうたくさん作っています。名前空間みたいなもの使って、キーワードを「.(ドット)」でつないで、「.(ドット)」のあるものは細かいやつ、「.(ドット)」のないものは大きなやつみたいに、ある程度キーワードの区分を付けています。

電卓の仕様が異なるので、同じテストケースが使用できないことがわかりました。それが答えが「9」になったり「7」になったりする問題です。この両方をやるために、どうするかですが、足し算とか掛け算とかのキーワードを追加することにしました。

足し算や掛け算のキーワードを追加することで、この2つの電卓で同じテストケースが使えるようになるのですが、なぜでしょう。

それはなぜかというと、「=」を押すからです。足し算、掛け算の時には、答えを出すことで使えるようになります。足し算、掛け算みたいなテストケースを書く時は、引数が2つ必要になるので、よく使うのがクエリストリングみたいなやり方です。これで引数としては1つだけど、値として2つ渡せます。

足し算というキーワードで2つのやつをやって、表示を3にする。次に掛け算で、今度は今のやつに掛け算で3を掛けていきます。

先ほどのところで、どういうことかをちょっと説明します。こちらは足し算で「1+2=」っていうのを押してしまうというかたちです。こちらも「=」を押してしまうかたちで、操作をすればできるのですが、実際に「=」を押すとは書きません。

そうしてしまうと、書き忘れた時に失敗してしまうわけですね。テストケースの書き方を簡単に書けなくなっちゃいます。ボタン操作とかを書いてやるやり方より、足し算のほうがたぶん粒度が大きくて、実際には中でボタン操作をしているということになるわけですね。

上のテストをそのままやっているわけではないのですが、掛け算や足し算という計算自体のテストにはなるので、これでも80点取れるかなと思います。

80点を取れるならそれをアリとする考え方があると思います。でも、どこまでのキーワードを作るかは、各プロジェクトやチームで考える必要があります。

あと、実際にはイテレーションを回すので、何回かイテレーション回す間に「こういうのをもうちょっとかけたほうがいいよね」と、かなり後で直すことが実際には多いです。

ちょっと話してしまったのですが、メリット・デメリットがあるので考えてもらえればと思います。

ヒントが先ほどの自由度と簡単にできるというところです。楽にできるってことと、すごくいろいろなことができるっていうところのバランスになります。

システムどうやって作っているかですが、各電卓用のDriverっていうものを作っていて、共通でできるところもありますし、実行するところを別にすることで、実行するところが論理的な識別子から具体的な識別子にですね、「1」というボタンが実は「Bの001」だったりするところの切り分けをします。

もう片方のほう、もしくは電卓のほうは、「B001」じゃなくて「ボタンの001」だったり、あるいは「単なる01」だったりするかもしれません。そういうかたちで、論理的なキーワードの解釈をする部分になります。

ここで解釈の処理を作ることで、テストケースを直さずに、Driverを直すことによってメンテナンスができます。新しいWebシステムのテスト作る時は、テストケースはそのままで、Driverだけ追加することで、異なったシステムで同じテストケースを走らせることができる作りになります。

ただ、Runnerのほうは特に特定のDriverを意識しないので、キーワードDriverの部分だけを意識して作ります。キーワードからElementに決定をするのは、ここのDriverが行っています。

SeleniumなんかでよくあるPageObjectにちょっと近いのですが、特定のページというよりも、もうちょっと汎用的なので、システムの作り方にもよりますが、いろいろなページでも使えるようになることが多いですね。

ただこの場合、当然「システム側の協力がないと論理的なものからIDへの変換ができない」とか「IDが時々乱数で作ってしまう」とか「難読化するためにID毎回違うんです」とか言われちゃうと、このDriverが作れなくなっちゃうのですね。「IDを振っていない」人とかシステムがあると、非常に作りづらくなってしまうので、そういう時はシステム側に直しを入れてもらうのがお勧めです。やはりそういう協力体制がないと、このあたりはツライところだと思います。こんなかたちでキーワード駆動のシステムは作れるかなと私は考えてます。

キーワード駆動テストのメリット・デメリット

ただ、欠点もあります。やはり作らなきゃいけないのね、自動システム。これがちょっとコストがかかります。利点は「作りやすい」とか、「ドメインで書けるのでいろいろなものに使える」とか、「さっきのDriverのところだけ直せばいいので、変更コストが抑えられる」とかです。

あと、もしかしたら自動生成もできるかもしれません。Markdownですと、組み合わせのテスト作る時は、「オールペア」を使って自動生成していました。こういったこともやりやすいですね。スクリプトだとなかなかこういうのはできないのですが、論理的なキーワードであればできます。

欠点は、作らなきゃいけない。また、けっこう開発コストがかかります。システム開発技術が必要になります。

今回ちょっと説明したように、実際のやりたいことによってキーワードの量が決まりますし、キーワードを採用するかどうかも本来は目的に合わせるので、目的をしっかり考えて「キーワード駆動を使うのか」「どんなキーワードを使うのか」「キーワードの量どうするのか」を考えてもらえるといいと思います。

今回はWebの電卓でしたが、違うやつで同じキーワード考えてもらうといいのかなと思います。もしかしたら2つ似たようなやつを使って、この2つで共通にできるものとか考えると、汎用的なものができるかもしれません。この演習のフレームワークというかやり方を、ぜひ1度検討してもらえると、訓練になるかなと思います。

自動化はここの作業で、どういうふうにテスト作るかは一緒です。このあたりの上位のところでキーワードきれいに洗い出せると、後のこの流しが自動になってきます。

目的はなにかをしっかりと定めることが大事

自動化はゴールじゃないですよという話です。やはり、目的をしっかり求める。何をしたいのか。何を効率化したいのか。DevOpsの場合は、何がボトルネックになっているのか、何が足を引っ張っているのか、その処理を流すのに人手が入ってしまっている部分とか、あるいは、止まるとか、処理が増えるとか、無駄が増えるところとかをしっかり理解して、その中で必要であればキーワードを使うのがお勧めだと思います。

ただ、やはりシステムテストって非常にコストがかかるので、そういう意味ではコストをかけても作ってみる価値はあるかなと思います。私のプロジェクトの中では、かなり効果は出ています。

きちんとルール決めましょうということですね。アーキテクチャって何かっていうと、品質特性を達成するためのもので、目標を達成するために具体的にどうするかというのがアーキテクチャなので、キーワード駆動導入するのは、1つのアーキテクチャをそのテストに導入するということになると思います。

それを入れるかどうか、目標に合っているどうかを気をつけないと、キーワード駆動を入れたくなっちゃって、なんでもいいからやっちゃうみたいになってしまうと本当に本末転倒になってしまうので、しっかり目標決めてやりましょう。

システムテスト自動化に回しだすと、実際にはいくつかのサブシステムが必要になります。要はテストするのと、テストを作成することもしなきゃいけないし、実行するのもあるし、実行した時に結果をどう収集するかとか、運用ですね。朝やるのか、何かが入った時にやるのか、チェックインされたらやるのかとか、リリースの前にやるのかということがあるので、この3つの部分は少し分けて考えたほうがいいかなと私は思っています。

なぜかっていうと、やりたいことがちょっと違うのですよね。関心事が違うので、テスト対象のシステムは、テストしやすいシステムであることをやってほしいし、スクリプトは作りやすくやりたくて、実行は確実に実行したいですよね。

運用はいろいろと上手に運用したい。システムによって違いますが、バグが見つかった時にすぐにどこが悪いのかわかるのが一番かっこいいのですが、なかなかそこは難しいところがあります。各々目的が違うので、ここは分けて考えるのはどうでしょうというのが私の考えです。

対象システムの場合はやはり、自動化することしっかり組み込みます。実際に回してみて、駄目だったら直してもらうことを最初から合意しておくのはすごく重要です。

テストスクリプトに対する理解性は、キーワードにするとかなり達成しやすいと思います。

やはり似たようなコードがたくさんあると、スクリプトをいっぱい直さなきゃいけないことになって非常に安定しないのですね。キーワード駆動の場合は、キーワードを解釈して動くところが1箇所にあるので、作るのはちょっと大変ですが、そこである程度の安定性を確保できる構成になってはいます。

運用は、だんだん数が増えるので並行してやりたくなったりしますが、このあたりはプロジェクトによって違うので、どういうことしたいのかを考えて、考えたらいいかなと思います。

これはあくまでも例なので、運用の全部ではありません。例として挙げているだけで、実際には各プロジェクトで「うちは効率がすごく大切だよね」じゃなくて「うちはなんか並列ですごくやりたい」とかそういうこともあるので、考えましょうということです。

実際に誰が担当するのがベストかというと、当然テスト対象のシステムは開発者が作るので、その人が作るのが一番いいのかなと私は思います。

テストスクリプトは誰が作るかというと、みんなが作るのが一番ですね。システム作ってる人もテストを作んないと大変さがわかんなかったりします。「あ、こんなテストしたいよね」という時に「あ、このキーワードだったらいいんだな」というかたちで、開発者のアイデアもQAの方たちのアイデアもたくさん入ってくるので、そういう意味ではいろいろな人がやるのがいいと思いますね。運用はCI/CD担当なので、開発者がやると思います。

目的を考えてルールを決めてみんなでやる

最後にまとめです。やはりきちんと目的を明確にしましょう。テストしたいシステムやプロジェクトによって目的は異なってきます。その目的がしっかり明確になったら、ルールと、どういうことをやりたいのか。効率化したいのか、自由に作れるようにしたいのかをしっかり決めましょう。それをきちんとみんなが守ることをルールとして決めましょう。

ルールを決めた時に、ルールと品質特性がつながってないと、なんのためのルールなのか、そのルールはいつ直したらいいのかがわかんなくなってきます。いわゆる学校の校則みたいに、校則が1人歩きしてしまって目的に合わなくなってしまうので、きちんと目的を合わせて考えることによって、ルールが直しやすくなります。

システムテストのアーキテクチャを作るのはすごくいいのですが、いくつかのサブシステムがあるので、そこを分けてやりましょう。

あとは、やはりみんなでやらないとうまくいかないですね。品質管理チームだけが自動化しようとか言うと、システム側がID振っていないとか、急にIDを振るの変えちゃうとか。テスト側の大変さがわからないと「なんかこのほうがかっこいいからやります」と言う人もいて、それはやめてほしいのでみんなでやりましょう。

非常に駆け足ですが、一応これで時間どおり終わりです。ありがとうございました。

司会者:貴重なお話、誠にありがとうございました。それではさっそく1つ目の質問です。「仕様がガンガン変わる開発プロジェクトでも、キーワード駆動テストの費用対効果はプラスになり得るかどうかが気になります」という質問がきています。

小井土:仕様変更ですが、全部が変わることは普通ないですよね。マリオをやっていて、いきなりドラクエをやったりしないじゃないですか。

例えばアジャイルみたいな開発をしていて、週次でリリースしたとしても、週1で全部の部分を作り直すのは不可能です。リリースがある程度、DevOpsみたいになっていれば、固まっている部分がたぶんあるので、そこにキーワード駆動を入れるという作戦はあるとは思います。

ただ実際には、テストのところでユニットテストとか結合テストとかのほうが書きやすいので、そちらで賄いたいならそちらをしっかりやるべきだとは思いますね。

システムテストをやる。そこができたうえで、さらにそのうえをやりたい時に行うものなので、バランスはしっかり考えたほうがいいかなとは思います。なので、費用対効果が出るかはプロジェクトによりますが、検討の余地はあるとは思います。

特にシステムの規模が大きい場合、キーワード駆動でしっかりテストのバックボーンを作っておくのは、お勧めではあります。ちょっとコストがかかりますが、やはり規模が大きいほうがいいかなっていう気はします。

司会者:ありがとうございます。