0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【JS/TS】突然変異テスト

0
Last updated at Posted at 2026-04-25

突然変異テストとは

テストの品質を測るテスト
実装の一部分に変更を加えて単体テストを実行し、各テストが落ちることを確認する。
テストの品質が高い場合、実装の一部が変わればテストは落ちる。しかし、テストの品質が低い場合、実装の一部が変わってもテストが通る。
本項では 突然変異テストと テストライブラリ Stryker について記載している

Stryker

突然変異テストのライブラリ
2026/4/25 現在はJavaScript, C#, Scalaをサポートしている

1. 準備

1-1. インストール

@stryker-mutator/coreと テストランナー用のライブラリ をインストールする
今回はvitestを使用しているため、テストランナー用のライブラリは @stryker-mutator/vitest-runner をインストールする(参考 : Stryker / Vitest Runner

$ npm install -D @stryker-mutator/core @stryker-mutator/vitest-runner

Jest など他テストランナーもサポートしているため、Strykerの各テストランナーのページを参照すると良い

1-2. 初期設定とコンフィグファイルの作成

npx init strykerで対話形式で初期設定を行う(参考 : Stryker / getting-started
対話が完了するとプロジェクトルートにstryker.config.jsonが作成される※
必要に応じていくつか設定を変更する

stryker.config.json
{
  "testRunner": "vitest",
  "vitest": {
    "configFile": "vitest.config.ts",
    "related": true
  }
}

※1 コンフィグファイルの形式はjsなどもサポートされている。Strykerのドキュメントの各コンフィグ設定が JSON ベースのため、jsonで作成。
※2 "vitest"."dir": "packages"は不要のため削除している
※3 コンフィグファイルのみ手作業で追加しても支障はない

1-3. .gitignoreに追記

突然変異テストの実行結果がreportsフォルダに作成されるため、追跡対象外とする

.gitignore
reports

2. 実施

2-1. 実装と単体テストの作成

  • 100以上の数値のみ抽出するメソッドと単体テストを作る
    テストライブラリは vitest を使用

    実装(バグあり)
    export function extractOverHundred(arr: ReadonlyArray<number>) {
      return arr.filter((a) => a > 100);
      //                   バグ:>=が正しい
    }
    
    テスト(境界値不足)
    import { extractOverHundred } from './common';
    it('100以上の数値のみ抽出する', () => {
      // 検証に「100」が含まれないため、バグに気づかない
      const arr = [99, 101, 1000];
      expect(extractOverHundred(arr)).toStrictEqual([101, 1000]);
    });
    
$ npx vitest run

  unit test  tests/common.test.ts (1 test) 4ms
     extractOverHundred (1)
       100以上の数値のみ抽出する 2ms

  Test Files  1 passed (1)
      Tests  1 passed (1)
    Start at  21:45:55
    Duration  234ms (transform 27ms, setup 0ms, import 45ms, tests 4ms, environment 0ms)
  • 検証内容に誤りはないためテストは通る

2-2. Strykerの実行

  • npx stryker run で突然変異テストを実行する
    実装に変異を加えたファイルを作成し、そのファイルに対して単体テストを実行してくれる

    全出力
    $ npx stryker run
    > stryker run
    
    21:53:13 (3368) INFO ProjectReader Found 2 of 20 file(s) to be mutated.
    21:53:13 (3368) INFO Instrumenter Instrumented 2 source file(s) with 7 mutant(s)
    21:53:13 (3368) INFO ConcurrencyTokenProvider Creating 11 test runner process(es).
    21:53:15 (3368) INFO DryRunExecutor Starting initial test run (vitest test runner with "perTest" coverage analysis). This may take a while.
    21:53:15 (3368) INFO DryRunExecutor Initial test run succeeded. Ran 1 tests in 0 seconds (net 3.4864000000000033 ms, overhead 297.5136 ms).
    Mutation testing  [==================================================] 100% (elapsed: <1m, remaining: n/a) 7/7 Mutants tested (1 survived, 0 timed out)
    
    All tests/common.test.ts
       extractOverHundred 100以上の数値のみ抽出する (killed 6)
    
    [Survived] EqualityOperator
    src/common/common.ts:9:28
    -     return arr.filter((a) => a > 100);
    +     return arr.filter((a) => a >= 100);
    Tests ran:
        extractOverHundred 100以上の数値のみ抽出する
    
    
    Ran 1.00 tests per mutant on average.
    -----------|------------------|----------|-----------|------------|----------|----------|
              | % Mutation score |          |           |            |          |          |
    File       |  total | covered | # killed | # timeout | # survived | # no cov | # errors |
    -----------|--------|---------|----------|-----------|------------|----------|----------|
    All files  |  85.71 |   85.71 |        6 |         0 |          1 |        0 |        0 |
    common.ts |  85.71 |   85.71 |        6 |         0 |          1 |        0 |        0 |
    -----------|--------|---------|----------|-----------|------------|----------|----------|
    
[Survived] EqualityOperator
src/common/common.ts:9:28
-     return arr.filter((a) => a > 100);
+     return arr.filter((a) => a >= 100);
Tests ran:
    extractOverHundred 100以上の数値のみ抽出する
  • [Survived]が実装に変更を加えてもテストが成功した記録
  • 「実装の >>= に変異させたとき、先ほどのテストが通った」と出力されている

3. 片付け

突然変異テスト実行時に作成されるファイルは不要のため削除する

$ rm -r .stryker-tmp

※ 1-2. 初期設定とコンフィグファイルの作成 で.gitignoreに本フォルダ名が追記されているため、追跡対象になることはない

所管

  • 境界値テストなどテスト作成時に考慮すべき観点が不足していないか自動で確認できるだけでも、突然変異テストは非常に有用であると感じた

参考・関連

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?