⚡️

Vitestで書いたテストに対してStrykerを利用したMutation Testingを試してみる

2023/10/24に公開

TL;DR

  • Mutation Test とは
  • 実際にStrykerという JS のライブラリを利用して、Mutation Test をやってみる

Mutation Test とは

Mutation = 突然変異 = コードを意図的に変更し、バグを植え付けること

だそうです。

Mutation Test においてはライブラリなどを利用し、コードの一部を意図的に変更します。

例えば、a===0a!==0のように改変する(=変異させる)といった感じです。

その後テストを実行し、正しくテストが書かれていたとすれば、結果は変異前と変わるためテストが失敗するはずです。

しかし、正しくテストが書かれていなければテストは失敗しません。

Mutation Test においてはこれを、KilledSurvivedと定義しています。

  • Killed
    • 変異後、成功すべきテストが失敗したことにより検知された変異の数
  • Survived
    • 変異後、失敗すべきテストが成功したことにより検知された変異の数

つまり、Survivedの数が多ければ多いほど、テストコードの品質が低いことを著しています。

以上から、Mutation Test を導入することで何がよいかというと、見かけ上のコードカバレッジが高く、作成したソースコード全般的にテストコードが網羅できていたとしても、テストコードが正しく書けているとは限らないので、その部分を担保してくれるということです。

例えば以下のようなテストコードはカバレッジ 100%ですがテストには全く意味がありません。

function addNewOrder(newOrder) {
  logger.log(`Adding new order ${newOrder}`);
  DB.save(newOrder);
  Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`);

  return { approved: true };
}

it("Test addNewOrder, don't use such test names", () => {
  addNewOrder({ assignee: "John@mailer.com", price: 120 });
}); //Triggers 100% code coverage, but it doesn't check anything

ここまでの話はjavascript-testing-best-practicesの内容を要約したものですので、よければ原文の方も見てみてください。

Stryker を利用した Mutation Test

まず公式が提供しているサンプルプロジェクトを利用して、実際に Mutation Test を実行してみます。

git clone https://github.com/stryker-mutator/robobar-example
npm install

ライブラリを install 後、まずはテストを実行します。

npm test

そうすると、カバレッジレポートがreports/coverage/lcov-report/index.htmlに出力されます。

レポートを確認すると、一見カバレッジが 100%のように見えます。

この 100%が本当に信じられる数値なのか?を今度は MutationTest を実行して確認してみます。

npm run test:mutation

そうすると、今度はreports/mutationディレクトリに実行結果が出力されます。

このレポートを確認すると、159件の変異のうち、killedされたのは86件だったので、実際のカバレッジとしては50%後半くらいであることが判明しました。

既存のプロジェクトに Stryker を導入する

では次は、既存のプロジェクトに Striker を導入してみようと思います。

私が個人的に運営しているこちらのリポジトリに入れてみようと思います。テストランナーはVitestを使っています。

https://github.com/ysknsid25/booby

ではまず現状のカバレッジを確認してみます。

なかなか優秀なカバレッジのようですが、これが本当に信じられる値かどうか Stryker に検証してもらいましょう。

まずはstryker-cliをインストール。

npm i -g stryker-cli

その後、Stryker を導入したいプロジェクトのルートディレクトリで以下を実行すると、対話形式で設定が開始されます。

stryker init

Stryker is currently not installed.
? Do you want to install Stryker locally? npm

             |STRYKER|
       ~control the mutants~

           ..####@####..
        .########@########.
      .#####################.
     #########################
    ###########################
    ###########################
    @@@#####################@@@
    ###########################
    ###########################
     #########################
      '######################'
        '########@#########'
           ''####@####''

Installing: npm install --save-dev @stryker-mutator/core

その後 3 つ質問されるので答えてあげます。

? Are you using one of these frameworks? Then select a preset configuration. create-react-app
? What file type do you want for your config file? JSON
Writing & formatting stryker.config.json...
? Which package manager do you want to use? npm

すると JSON で以下のような設定ファイルが作成されます。

stryker-config.json
{
  "$schema": "./node_modules/@stryker-mutator/core/schema/stryker-schema.json",
  "_comment": "This config was generated using 'stryker init'. Please see the guide for more information: https://stryker-mutator.io/docs/stryker-js/guides/react",
  "testRunner": "jest",
  "reporters": ["progress", "clear-text", "html"],
  "coverageAnalysis": "off",
  "jest": {
    "projectType": "create-react-app"
  }
}

この状態でテストを実行すると、testRunnervitestになっていないのでテストが失敗します。また、vitestに変えてあげても失敗します。

どうやら追加でvitestのテストランナーを入れてあげないとダメらしいです。

https://stryker-mutator.io/docs/stryker-js/vitest-runner/

npm i --save-dev @stryker-mutator/vitest-runner

この状態でstryker runをするとテストが実行され、先ほどと同じくreport/mutationディレクトリにレポートが作成されました。

かなりMutationが生き残ってしまっており、実は有効なテストになってなさげな箇所があることがわかります。

それがどこかを確認しましょう。

ファイル名をクリックすると上記のような画面が表示され、赤線部分が Stryker による変異箇所です。

差分形式で表示されているのでわかりやすいですね。

これをみながら、「どういった変異に対してテストが有効にできていないか?」を修正していく必要があります。

これは後ほど地道に直していきます、、、

おわりに

見かけ上のカバレッジが信用に足りない可能性があり、テストの品質を上げてくれるのは嬉しいなと思いました。

Kotlin にも Mutation テストをかけるライブラリがあるのか、また調べたいです。

メンバー募集中!

サーバーサイド Kotlin コミュニティを作りました!

Kotlin ユーザーはぜひご参加ください!!

https://serverside-kt.connpass.com/

また関西在住のソフトウェア開発者を中心に、関西エンジニアコミュニティを一緒に盛り上げてくださる方を募集しています。

よろしければ Conpass からメンバー登録よろしくお願いいたします。

https://blessingsoftware.connpass.com/

Discussion