
シェア:
マックスはPythonデベロッパー・アドボケイトであり、通信API、機械学習、デベロッパー・エクスペリエンス、ダンスに興味を持つソフトウェア・エンジニアだ!物理学を専攻していたが、現在はオープンソースのプロジェクトに携わり、開発者の生活をより良くするためのものを作っている。
あなたのソフトウェア・エンジニアリング・スキルを向上させるために、変異テストを活用しよう!
所要時間:1 分
コードカバレッジ(テストを実行したときに実行されたコードの割合)は、すばらしい指標です。しかし、カバレッジだけでは、テストがコードベースの変更をどれだけうまく検出できているかはわかりません。テストがうまく設計されていなければ、ユニットテストに合格しても本番環境は壊れてしまいます。
変異テストは、テストをどれだけ信頼できるかを定量化するための、すばらしい(そして過小評価されている)方法です。変異テストは、コードを微妙に変化させ、その「変異した」バージョンのコードに単体テストを適用することで動作します。もしテストが失敗したら、それは素晴らしいことだ!もしテストが通ったら、それはあなたのテストがこの変更を検出するのに十分でなかったということです。
このビデオでは、Vonage Developer ExperienceチームのMaxが、どの言語でも変異テストを始める方法と、CI/CDパイプラインに統合する方法を紹介します。すぐに、変異コードをキャッチすることは、あなたのリリース・エンジニアリング・プロセスの日常的な一部となり、ペンギンを同じように見ることは二度とないでしょう!
以下は、ビデオのトランスクリプトといくつかの便利なリンクである。
Vonageの無料開発者アカウントはこちらからサインアップできます。.
ご質問があれば コミュニティSlackまでご連絡ください。.
こんにちは、私の名前はマックスです。Vonageでデベロッパー・アドボケイトをしています。今日は突然変異テストについてお話ししたいと思います。私がどのようにそれを使っているのか、そしてあなたがどのようにそれを使うことができるのか、お話ししたいと思う。始める前に、私が勤めている会社について簡単に触れておこう。
私たちはVonageという会社で、通信APIなどを扱っています。ですから、私が扱うコードの多くは次のようなものです。 SMSを送ったり、音声通話をしたり、ビデオチャットを作ったり。といったものです。だから、コミュニケーションに関係するものがたくさんあるんだ。なぜこの話をしたかというと、実際に変異テストをコードに適用したからなんだ。その方法と、なぜそれが僕らにとって良い選択だったのかを紹介したい。でもその前に、この話の本当の主人公を紹介したい。
私は話し手だが、本当の主人公は実はヘンリーだ。これがヘンリーだ。かわいらしい小さなペンギンであることがお分かりいただけると思います。彼がここで本当に重要なキャラクターである理由は、私自身が突然変異検査を学ぶ中で、ヘンリーをいろいろなことの例えとして使っていたからです。その理由は、今日も彼を使って突然変異試験が実際にどのように機能するかをお見せするからです。始める前に、いくつかの基本線を設定しておこう。
まず最初に、テストという言葉を聞いたことがあるだろうか?このビデオをクリックした方、このビデオを見ている方は、おそらくソフトウェアのテストとは何かをご存知だと思います。
コード・カバレッジについても考えてほしい。コード・カバレッジを知っている人も知らない人もいるかもしれない。もし知らなくても心配しないでほしい。コード・カバレッジについては、これから必ず触れることになるからだ。変異テストもある。このビデオのタイトルを見た人は聞いたことがあると思いますが、これは本当に便利なものです。このビデオが終わるころには、突然変異検査についてもっと多くのことを知り、自分でも使ってみたくなっていることでしょう。そう思っていただけたなら、続けましょう!
私がやりたいのは、ちょっとした基準値を設定することだ。まず最初に、テストについて触れたいと思います。なぜユニットテストを書くのか?コードのテストを書く理由は何だろう?一旦立ち止まって、自分で考えてみるのもいいかもしれない。そうでないかもしれない。それでも構わない。
その場合は、私が考えていることをお見せしましょう。そしてこれが私の手元にあるものだ。つまり、コードが機能することを証明するためにコードを書くことができる。コードに自信を持たせるための文書化、リグレッション・テスト、リファクタリング、そしてコンプライアンス上の理由でも書くことができる。
基本的に、ユニットテストを書くことを勧めるようなものはすべてここにある。コードが動くかどうかを検証する方法があるのは素晴らしいことだ。文書化する方法があるのも素晴らしいし、これらすべての素晴らしいことがある。しかし、ここにもちょっとした問題がある。最初は小さなプロジェクトで始めるかもしれないが、そのプロジェクトは急速に大きくなる可能性があり、そのプロジェクトが行うことは時間とともに進化していく可能性があるという問題だ。そして、リファクタリングなどをしているうちに、コードを見逃したり、セクションを飛ばしたりするかもしれない。見落としがあるかもしれない。すべてのコードをテストしなくなってしまうかもしれない。ここで問題になるのは、テストをモニターしていないことだ。
テストをモニターしなければ、テストする方法がないため、今あるコードのどこが悪いのかわからないし、テストが役に立つのかどうかもわからない。というわけで、ここで何が課題なのかがわかるといいのだが。コード・カバレッジがあるからこそ、良くなるのだと言いたいですね。コード・カバレッジとは何なのか、よくわからないかもしれないので、簡単に説明しよう。これは私の言葉で言うと、「テスト・スイートを実行したときに、プログラムのソースコードのどれだけが実行されたか」ということです。これが私の説明の仕方だ。
しかし、実際にその話をするのはやめて、実際の例をお見せしよう。 これは私が保守しているオープンソースのSDKの一つである。.基本的に、これは様々なAPIコールを行うためのPython SDKだ。このSDKで私がサポートしているAPIは メッセージAPI.その中で、SMS、MMS、WhatsApp、Facebookなど、さまざまなチャネルを使ってメッセージを送ることができる。コードを入手し、コード・カバレッジ・メトリクスを実行して、テストしているコードのどの文があって、どの文が抜けているのかを確認しました。ここで、私がほとんどをカバーしていることがわかりますが、23行目に欠落しているステートメントがあります。
この場合、そのような認証は試していない。ということは、そのテストを書くことができるということです。コード・カバレッジはすでに私のコードを改善している!他にできることは?
プロジェクト全体の概要と、その中のさまざまなステートメント、つまり基本的にどれだけのカバレッジがあるのかを知ることができます。私の場合はこんな感じです。これは素晴らしい。なぜなら、まず第一に、より多くのテストとより良いテストを書くことができるからです。
また、このような測定は実に簡単で安価だ。コード・カバレッジを実行して、「私は何をカバーしたのか」と言うだけで、計算量はそれほど多くありません。もうひとつの良い点、本当に良い点は、テストしなかったことがわかることです。もしこのコードを信用できないなら、本当は信用しないほうがいい。これは本当に便利だ。コード・カバレッジは実に多くのことをカバーしている。
ということで、実は、もうここで終わりにしようかと思います、ありがとうございました。今日は話せてよかった。また会いましょう......ただし、実はこれにはあまり良くないこともあるんです。
まず第一に、コード・カバレッジは少し誤解を招きやすい。また、テストの質を保証するものでもありません。そこで、非常に単純なPythonコードの例をお見せしましょう。ここでやっているのは requestsモジュールをインポートしています。
そして、そのライブラリを使ってAPIコールをする。私がしていることは、特定のURLにGETリクエストをして、レスポンスを返してもらい、そのレスポンスのJSONをユーザーに返しているだけです。それでいいんです。それでいいのです。次のスライドでは、次のページでテストしています。
実際にはカバレッジは100%だが、あまり役に立たない。APIを呼び出すものがある。しかし実際にやっていることは、APIを呼び出して、それを呼び出したらOKということだ。つまり、そのコードが実行されれば、それでいいのだ。しかし、戻ってくる可能性のあるものを検証することはできない。
200点の返事が返ってくるかもしれない。400点かもしれない。それ以外かもしれない。私たちが予期していないものが返ってくるかもしれない。そのような場合のテストもしない。ですから、このテストはあまり役に立ちません。
あるコードを書いた後、そのテストが役に立つからではなく、コード・カバレッジをもう少し高くする必要があったから、そのコードのテストを書いたことがあるだろうか?私はやったことがあるし、多くの人もやっている。もしそうでないなら、私はあなたを誇りに思うが、現実にはほとんどの人がこのようなことをしている。
コード・カバレッジで起こりがちなのは、カバレッジを洞察力を与えてくれるものではなく、むしろ目標にしてしまうことだ。この原則には名前がある。グッドハートの法則」と呼ばれるものだ。テストカバレッジに限ったことではありませんが、要するに「メトリクスがターゲットになったとき、それは良いメトリクスではなくなる」ということです。
これは本当に重要なことなので、もう一度言う。「指標が目標になったとき、それは良い指標ではなくなる」。さて、どういうことか?つまり、コード・カバレッジはコードとテスト、そしてそれらがどのように機能するかを教えてくれるはずのものだが、実際にはそれを最適化を気にする数値に変えてしまったということだ。
つまり、より良いテストを作ろうと考えるのではなく、数値を最適化しようと考えているわけだ。そうなると、いくつかの疑問が出てくる。たとえば、テストが実際に何をしているのか、どうやって理解すればいいのか?テストが信頼に足るものであるかどうかは、どうすればわかるのか?そして実は、これを最もよく言い表しているのは、紀元100年頃にローマの思想家ユヴェナールが(ワインを4杯目飲んだ後に)考えたもので、彼が思いついた文は「誰が監視者を監視するのか」というものだった。私たちの面倒を見るべき人たちの面倒を誰が見ているのか。同じように、誰が我々のテストをテストしているのか?
その答えとは、突然変異検査である。さて、ヘンリーが少しばかり再登場したことにお気づきだろうか。
まず第一に、彼はかわいいし、もっと重要なのは、これから私たちを助けてくれるからだ。昨年、突然変異検査について学び始めたとき、それを自分のコードにどのように適用できるかをとても考えていた。その方法とは、基本的に多くのAPIコールを送信し、APIコールやメッセージを処理する自分のコードを、ハトやハトのような、飛ぶことができる鳥のようなものだと想像することだった。この例えの中で私ができることは、鳥の足にメッセージを結びつけて鳥を放すことだ。
だから飛んで行って、私が必要とすることをしてくれる。さて、ペンギンの問題は、彼らは鳥なので、その基準を満たしているのだが、ご存知のように彼らは飛ぶことができない。しかし、もっと重要なのは、このような突然変異は、普通の鳥がペンギンに変わったようなもので、鳥が飛ぶという、私が必要とする中心的なことができないのだ。鳥の写真を使って実際の例を見てみましょう。
まず、期待通りに動作するプロダクション・コードから始める。次に、ある種の突然変異操作を行って、このコードの突然変異バージョンを作成する。例えば、これはPythonの関数だ。これは単に2つの数値を足して、その和を返すだけです。さて、これを変異させたバージョンは、例えば数値を引いたり、定数を追加したり、2つの文字列の足し算を返したりするかもしれない。
まったく何も返さないかもしれないし、そのコード行が返すものを変えるような論理演算をするかもしれない。では、突然変異テストで何をするのか?変異体をいくつか作ったが、次は何をすればいいのか?
では、今あるミュータント(変異体)を使ってみよう。これらをファブ4と呼びますが、その理由は明らかでしょう。それぞれの変異体を取り出します。この例えで本質的にやっていることは、その変異体が飛べるかどうか、飛び立ってメッセージを運ぶために必要なテストに合格できるかどうかを見ることです。つまり、この美しいミュータント・ペンギンのヘンリーは、飛んでみる必要があるのです。
だから、このミュータントを使ってテスト・スイートを実行する。最高のシナリオでは、テストは失敗する。これはヘンリーの正体を暴いたということであり、愛らしいペンギンであるということだ。というのも、ヘンリーを本番には出さないということだからだ。というのも、ヘンリーがハトではなくペンギンであることに気づかなかったからだ。
そして彼は空を飛ぶことができる。つまり、この翼を見てください。このペンギンはバスを持ち上げることができるんですよ。とても印象的だ。しかし、それはこの突然変異体が生産に入る可能性があるということであり、それは我々が望まないことだ。では、これは何をもたらすのか?
そして、このことが私たちに与えてくれるのは、検査の質を評価する方法だと断言する。それが突然変異検査なのだ。
フレームワークについて考えてみましょう。フレームワークには、様々な言語に対応する様々なオプションがある。私の場合は、Pythonベースの変異テストフレームワークであるmutmutを使っています。
でも他の言語に興味があるなら、Java用のPitestやJavaScript用のStryker、C#などがある。つまり、複数の言語に対する選択肢があるわけだ。もしその言語について言及されていなくても、おそらくその言語に対応したものがあるはずだ。さて、私はプロの医者でもファイナンシャル・アドバイザーでも教師でも何でもない。しかし、私にとって最も重要なことは、私が使用したものについて話すことである。
というわけで、今日はmutmutについてお話しします。私がやったのは、この変異テストを自分のSDKに適用することでした。まず最初に pip install mutmutこれはPythonicなインストール方法で、これを実行します。これだけです。
幸運なことに、このソフトにはいくつかの賢明なデフォルト設定があり、変更する必要はなかった。あなたが何をするかによって、そこにあるものを変更する必要があるかもしれない。いろいろなコンフィギュレーション・オプションを選ぶことができるが、私にとってはこれで十分だった。これを実行すると、基本的に何が起こるかを教えてくれた。こう出力された。
まずタイミングなどを把握するために、テスト・スイート全体を実行するという事実をプリントアウトした。それから変異体を生成してチェックする。ここで出てくる結果にはいくつか種類があります。例えば、変異体を捕まえることもできますし、変異体がタイムアウトすることもあります。この場合、ミュータントを捕まえられなかったという本当に悪い状況です。このテストを実行すると、まず私のテストスイートが実行され、次にこれらの変異体がチェックされ、512個の変異体はキャッチできたが、170個の変異体はキャッチできなかった。さて、これについて考えてみよう。
それは良い数字なのか、それとも悪い数字なのか?それについては後で話すとして、今はミュータントを見てみよう。ここで、私たちが捕まえることができた簡単なものを紹介しましょう。まずはここから。これはMessages APIクラスです。
メッセージを送るのに有効なチャンネルがいくつかある。ミュータントはそのうちの1つを変えただけなんだ。文字列の1つを変えてしまったんだ。だからSMSでメッセージを送ることができなくなってしまった。それでそのテストをしたところ、失敗しました。
つまり、私たちがそう呼んでいるということだ。もうひとつ。Pydanticは素晴らしいバリデーションライブラリで、SDKでも使っています。これはPydantic V1で、数字を丸めるバリデータがあります。しかし変異版ではこのアノテーション、デコレーター(言語によって呼び方が異なりますが、Pythonではデコレーターと呼んでいます)が削除されました。
そこで、それを削除した。その結果、このコードが呼び出されることはなくなり、四捨五入のテストがあっても呼び出されることはなくなった。それでこれも失敗した。というのも、このコードベースには2つのバージョンがあり、2つの小さなヘンリーがいて、それを捕まえて「君はペンギンだ」と言うことができたからだ。
では、ミュータントをどう見るか?それは mutmut show変異体のリストが表示されます。例えば、1番を表示させれば、最初のミュータントが表示され、それを見ることができます。もちろん、これは簡単に捕まえられる。しかし、本当に面白いのは、これらすべてのテストの出力を見ることができることだ。
HTML形式のレポートができました。使用している言語や突然変異検査ソフトウェアによって、これを実行するのは簡単だったり難しかったりします。私たちの場合は非常にシンプルなインターフェイスですが、基本的にできることは、各ファイルの中で捕まえられなかった変異体をすべて表示するということです。それではいくつか見てみましょう。
これが変異体58で、これは捕まえられなかった。この変異体は、ロガーの名前を変えただけです。ロギングは私のテストの範囲外です。だから、この変異体が入ってきても気にしない。
それでいいんだ。別の例を挙げよう。これはミュータント62です。この中でやっているのは、定数の値を変更することだけです。繰り返しますが、これは私がテストしたい範囲ではありません。
デフォルト値が設定されているかどうかをテストすることは、私にとって重要ではないと思う。この文脈では、それは私にとって重要ではない。しかし、もっと重要で、私が気にするものを見てみよう。それがこちら。これはミュータント112だ。
ここでやっているのは、私たちが使っているすべてのAPIのクラスのインスタンスを作っているということです。ここにvoiceクラスがあるのがわかるだろう。ミュータント・バージョンでは、voiceクラスを作成していませんが、voiceメソッド用のクラスを作成していないにもかかわらず、テストはパスしています。では、なぜこのようなことが起こるのでしょうか?
なぜ私のテストは失敗しないのか?どうしたんだ?さて、私たちがこれを使う方法とSDKでテストする方法は、実はクライアントのオブジェクトを通して呼び出すだけではないことがわかりました。実際にはVoice APIクラスを直接呼び出しますが、ユーザーはこのように呼び出します。というわけで、本当はこのためのテストが必要なんですが。
というのも、このケースに対応するテストを書くことで、ユーザーが行うであろうことを代表するようなテストを書くことができるからです。では、この数字に戻ってみましょう。すると、たくさんのミュータントが見つかりました。また、かなりの数の変異体は捕まえられませんでした。実際には、これらの変異体の約75%しか捕まえられませんでした。
実際には約25%を逃した。この数字でいいのか?75%.これでいいのか?もしあなたがこれを見て肩をすくめているのなら、それが正しい答えです。
ここで興味深いのは、100%では意味がないということだ!だって、気にしない場合もあるでしょ?ロガーとか、変化する定数とか。それはどうでもいい。なぜなら、コード・カバレッジ・スコアの問題をまた抽象化してしまっただけだからだ。私が本当に気にしているのは、自分のコードに対する正しい洞察を得ることだ。
もしそうでなかったとしても、心配しないでほしい。でも、もしそうでなかったとしても、心配しないでください。これから紹介するのは、突然変異テストを始める方法です。まず最初に、大まかなアドバイスとして、ローカルで始めましょう。私もそうした。まずは小さく始める。もしあなたが私よりも大規模なテスト・ベースを持っているなら、あるいは大規模なテスト・セットを持っているなら、それらのサブセットから始めるといいだろう。また、パフォーマンスのために微調整をしたくなるかもしれない。そのため、自分に関係のない特定のテストを除外したくなるかもしれない。例えば、統合テストのようなものは、あまり気にしないかもしれない。
あるいは、コードの一部を除外したい場合もあるだろう。たとえば、いくつかのコードを自動生成した場合、おそらくそんなことは気にしないだろう。
マシンを暴走させたくなったとき、そうなるかもしれないが、このパートは本当に役に立つ。まず第一に、私はこのペンギンの写真にとても満足している。なぜこのような形で存在しているのか分からないが、とても嬉しい。
しかし、なぜマシンを止めたいのか?教えてあげよう。テストには時間がかかる。テスト・スイートを実行したいときは、自分のマシンを使うよりもクラウドのリソースを使った方がいいかもしれない。これはCIシステムに追加できるということでもあり、とても便利だ。
つまり、異なるプラットフォーム、異なるOS、異なるバージョンの言語、異なるバージョンのコードを指定できるのだ。では、これをお見せしよう。なぜそれが有利なのかは説明した通りだ。では実際に、私が何をどうやったかをお見せしよう。
これをPython SDKに適用してみた。そして、GitHubアクションを作成した。これはどんなCIシステムでもできます。私はGitHub Actionsを使っている。突然変異テスト用のアクションを作りました。基本的に、このアクションでできることは、テストスイートに対して突然変異テストを実行するかどうかを手動で選択することです。そして実際に、手動で実行することを選択しました。
自動実行はさせたくない。プッシュで実行させることもできますが、私はそうしないことにしました。だからこれを実行すると、実際にそのジョブが完了するのがわかるだろう。また、HTMLレポートも作成してくれます。ダウンロードできる実行アーティファクトとして提供されるので、テストのパフォーマンスや、どのミュータントが捕捉されていないかを正確に把握することができます。
では、どうすればいいのか?これが本当に興味深い質問だ。私が使った YAML をお見せしましょう。繰り返しになりますが、私は GitHub Actions を使っています。私自身が使っているものですが、好きなCIシステムでこれを行うことができます。そして正直なところ、私がメンテナンスしているSDKに自由にアクセスしてください。コードはそこにあります。YAMLファイルもあります。そして自分で使ってください。これで突然変異のテストを始めれば、みんなが得をする。いずれにせよ、今すぐYAMLをお見せしましょう。各パーツが何をしているのか、どのように機能するのかを説明しよう。
まず最初に、変異テストのYAMLをご覧ください。Ubuntuで実行されていることがわかります。Pythonのバージョンは1つだけです。異なるステップをここで見ることができます。コードをチェックアウトし、Pythonをセットアップします。
これが完了したら、依存関係をインストールする。 mutmut.これができたら、実際に変異テストを実行する。 mutmut runそこで2つのフラグを使う。を使います。 --no-progressこれは基本的に、CIシステムで読み返したときに出力がよりよく見えるようにすることを意味する。また --CIモードも使います。に私が貢献したのはこれだけなので、強調しておきます。 mutmutへの私の唯一の貢献だったからだ。そうしないと適切なエラーコードが得られず、GitHub Actions が失敗してしまうからです。そうしないとエラーコードが正しく表示されず、GitHub Actions が失敗してしまいます。これで終わりです。たった35行、これだけです。
CIについて、他にどんな懸念があるか?他に考えたいことは?まず第一に、手動と自動のトリガーについて考えたい。個人的には、このようなことは手動で行いたい。なぜなら、このようなことをPRプロセスの一部にしたくないからだ。
何か新しいことを追加して状況が変わるかもしれないときや、自分のコードに対する洞察が必要なときに実行したい。必要であれば自動で実行することもできるが、その必要はないということだけは認識しておいてほしい。またグッドハートの法則を抽象化し、突然変異スコアを抽象化するための新しい指標に変えようとは思わない。また、複数のOSで動作させることも考えたい。というのも、OSを弄るようなことはしないからだ。OSを弄るわけでもないし、APIを呼び出すだけだから。また、複数のバージョンの依存関係やそのようなものを使って実行してみて、自分にとって何か変化があるかどうかを確認するのもいいかもしれない。
要約すると、突然変異テストはテストをテストする。コード・カバレッジでグッドハートの法則に打ち勝つのに役立つ。もし使いたいのであれば、小規模でローカルなところから始め、準備ができたらCIシステムで実行することで、非同期でテストを終わらせることができ、マシンの時間とリソースを無駄にしなくて済む。最後に、ミュータントは貴重であり、素晴らしいものでもあると言いたい。ヘンリーとヘンリーが与えてくれたものすべてについて考えてみると、たとえば、ヘンリーは飛べないし、私たちが必要とするコードの仕事はできないけれど、ヘンリーがしてくれたことは、私たちのコードベースに対する多くの洞察を与えてくれた。だから、このプレゼンテーションの最初に言ったように、ミュータントを恐れてはいけない。
ありがとうございました。今日、皆さんとお話できて本当に本当によかったです。ご質問などありましたら Vonage Community Slackにご参加ください。.もし Python SDKをご覧になりたい方はこちらもどうぞ。そして Vonageのアカウントを作ってまた、Vonageのアカウントを作り、私たちのものを試してみたい場合は、ここにもリンクがあります。
だから、これらのことがあなたにとって役に立つことを願っている。ありがとうございました。また別の機会にお会いしましょう。ありがとう。


