2.9K Views
October 18, 24
スライド概要
2024/10/18 iOS Test Night #13の登壇資料
自動テストの信頼性を高める ミューテーションテストの活用に向けて 2024/10/18 iOS Test Night #13 tarappo
自己紹介 平田敏之(tarappo) かんたんな経歴 • DeNA SWET → 10X → SmartHR 担当領域 ・「開発生産性の向上」「品質の担保」をミッション
はじめに • • みなさん、自動テスト実装していますか? ここ数年でモバイル界隈においても自動テストを実装する機会は増えてきているか と思います さらに • Xcode16から待望の「Swift Testing」が利用できるようになりました これで、自動テストをもっと実装できるようになりますね
はじめに そこで質問です • 自動テストはちゃんと必要なテストケースを考えて作っていますか? • 今ある自動テストで • • なにかあったときに問題を見つけられる自信がありますか? コードカバレッジの数値で問題ないと判断したりしていませんか? そこでミューテーションテストを試してみましょう
ミューテーションテストとは? • テストコードの十分さを測定するための手法 • プロダクトコードに変異を入れたときにそれをテストコードで検知できるかどうか • 変異=ミュータント • 変異を入れるとは? >を<に変更 このように変更されたときに「テストコード」で検知できますか?
ミューテーションテストとは? • 変異を入れたコードに対してテスト実行 • テストが落ちる(=Killed) • テストが落ちない(=Survived) • Survivedの数が多いほど課題があるともいえる • KilledとSurvivedの割合をみてMutation Scoreが決まる • Killedした数 / 変異を入れた数 = Mutation Score
ミューテーションテストにおける変異のパターン • パターン例 • AOR:arithmetic operator replacement • 算術演算子置き換え • a + b → a - b、a/b などに変換 • LCR:logical connector replacement • 論理結合子置き換え • a && b → a || b などに変換 • ROR:relational operator replacement • 関係演算子置き換え • a > b → a < b、 a == b などに変換
ミューテーションテストのためのライブラリ Stryker(https://stryker-mutator.io/) • • JavaScript、C#、Scala PITest(https://pitest.org/) • • Java and JVM Mull(https://github.com/mull-project/mull) • • C、C++ mutation̲test(https://pub.dev/packages/mutation̲test) • • Dart
iOSにおけるミューテーションテスト • ライブラリ • https://github.com/muter-mutation-testing/muter • セットアップと実行までの流れ • インストール • 設定ファイルの用意(muter.conf.yml) • 実行コマンドの指定 • 対象外ファイルの指定 • 実行 • $ muter --format html --output ./result.html
サンプルコード 現時点での仕様 • 100円で1ポイントが手に入る • ポイント上限は200ポイント • 50000円をこえる購入者は300ポイント • 次のいずれかの条件を満たせばポイント2倍 • • • 年齢が60歳以上 ランクが10を超えている
テストを考えてみよう • case1 case2 case3 case4 「単純に」カバレッジ100%にしてみる • case1)0円のときはポイント0 • case2)60歳以上のときかランクが11以上のときにポイント2 倍 • case3)50000円をこえるとき300ポイント • case4)20000円以上で50000円以下の購入金額は200ポイント case1 case3 case4 case2
テストの実行結果 テストの実行結果 case1 case2 case3 case4 カバレッジ結果(100%) これでテストケースは足りていますか?
テストケースは足りてますか? • • case1 case2 • • case1)0円のときはポイント0 case2)60歳以上のときかランクが11以上のときにポイント2 倍 case3)50000円をこえるとき300ポイント case4)20000円以上で50000円以下の購入金額は200ポイント case3 case4 ここで ミューテーションテストをやってみましょう
muterの実行結果(レポート) 次の変異を入れた際にテストが失敗してい • ない • • user.age <= 60に変えたとき user.rank < 10 に変えたとき
テストコードを見直してみよう 次の変異を入れた際にテストが失敗してい • ない • • case1:user.age <= 60に変えたとき case2:user.rank < 10 に変えたとき 年齢の境界値を見ているようで見ていない • 60歳と59歳を使っているが片方は金額上限を見ているだけ • ランクについては特になにも見ていない • rank10をこえるテストケースが1つもない •
テストコードの追加 次の変異を入れた際にテストが失敗してい • ない • • • case1:user.age <= 60に変えたとき case2:user.rank < 10 に変えたとき ポイント上限を見るテストケースと上限を見ない ケースでテストをわけて追加 • ランクについてのテストケースも追加
(再度)muterの実行結果(レポート)
muterにおける変異パターン • muterでは次のパターンを用意しています(一部のみ記載) • • Negate Conditionals • Change Logical Connector 参考:https://github.com/muter-mutation-testing/muter/blob/master/Docs/mutation̲operators.md
ミューテーションテストにおける課題(の一つ) ミューテーションテスト自体の考えは歴史が浅いわけではない • なぜ、そこまで利用されてなかったのか 「変異」をプロダクトコードに入れて、テストコードを実行する • • • → 変異を入れた数だけ実行時間は増えていく → おこなうのに「実行時間」が課題になるケースが多い しかし • 昨今の「マシンパワー」(など)により実現可能になってきている(ともいえる) iOSのテストではどうなのか?
iOSの自動テストの課題 • 自動テストの実行の流れ • 単純に「変異」を入れた場合の流れ 「変異」が2種類でも実行時間の増加が激しい どうするとよいのか?
実行時間に対するアプローチ 課題 • • 毎回、変異を入れてテストの実行をしていては時間がかかりすぎてしまう muterではどのようなことをおこなって実行時間の短縮をおこなっているのか • • • (1) (2) ビルドとテスト実行の分離 起動時環境変数の利用
実行時間に対するアプローチ (1) • ビルドとテスト実行の分離 ビルドとテスト実行の分離(Xcode8から) • build-for-testing:ビルド • test-without-building:ビルドされたものをテスト実行
実行時間に対するアプローチ (2) • 起動時環境変数の利用 変異を最初に用意 • 起動時環境変数で実行するコードを分岐 • (A)、(B)のところ
実行時間に対するアプローチ (2) • 起動時環境変数の利用 muterの変異の入れ方 • プロダクトコードに全ての変異を入れる • 起動時環境変数で呼び出すコードを制御する xctestrunファイル 起動時環境変数 変異を入れたあとのプロダクトコード
実行時間に対するアプローチ (2) • 起動時環境変数の利用 変異数に対応する「起動時環境変数」が指定される • 実行ケース1:(A)に対応する起動時環境変数をxctestrunに設定 • 実行ケース2:(B)に対応する起動時環境変数をxctestrunに設定
実行時間の短縮効果 短縮時間 ここを並列化できればさらに短縮は可能
ミューテーションテストの効果 メリット • テスト漏れに気づけることがある • • テスト設計が「不十分」「苦手」なときには効果大 コードカバレッジとは違った自動テストのFB • • ※コードカバレッジと併せて使うと良い
ミューテーションテストでの注意点 扱う際の注意点 • 自動テストが一定あることが前提 • • カバレッジと併せて利用すると良い どういった変異パターンがあるかはライブラリの実装次第 • ミューテーションスコアが100%であれば問題ないというわけでもない • 実行時間の長さ • • 実行対象は絞る必要がある 検知したものが全て直すべき対象とは限らない=チェックするコストがかかる • • 等価ミュータントのケースもある
ミューテーションテストでの注意点 実行時間の問題 muter側での対応はあってもどうしても実行時間はかかります • 実行時間:(1)実行対象のファイル数 × (2)変異パターン × (3)テスト ケース数 • (1)に対してのアクション • 実行対象外のファイルを設定 • muterでは設定ファイルで指定 • 実行する対象ファイルを指定 • --files-to-mutateオプションで指定 • (2)に対してのアクション • 変異パターンを絞る 実行対象を絞ってもCIでの実行時間は一定かかる • --operatorsで指定 「いつ」「どこで」実行するべきかは考える必要がある
ミューテーションテストでの注意点 検知したものが「価値」があるかの確認 • 「Survived」になっているケースがテストコードを追加するべきものかを調べる必 要がある • 対応をしても100%にならないケースは一定ある • 例)等価ミューテーション:変異させても結果が変わらないケースもある これを加味した上でどういったふうに利用するかを考える必要がある
おわりに • • • 自動テストはあたりまえの時代になりつつあります 今まで以上に「テスト設計」は重要であり「テスト技法」も重要です ミューテーションテストも使って自動テストをもっと活用していきましょう