SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

あらゆるソフトウェア開発者のサポートを目指す開発ツール「Visual Studio 2015」特集(AD)

ドキュメントがないコードの保守を任されても安心
~テストコードを網羅的に自動生成するVisual Studio 2015 Enterpriseの「インテリテスト」機能

あらゆるソフトウェア開発者のサポートを目指す開発ツール「Visual Studio 2015」特集 第2回

  • このエントリーをはてなブックマークに追加

簡単なサンプルを使ってインテリテストを体感する

 では早速インテリテストがどんなテストを生成してくれるのか、試してみましょう。今回は、FizzBuzz(フィズ・バズ)問題と呼ばれるシンプルなコードを対象にします。FizzBuzz問題とは、1から100までの整数について、以下の文字列を出力するコードを記述する問題です。

  • 3の倍数の場合は"Fizz"を出力
  • 5の倍数の場合は"Buzz"を出力
  • 3の倍数でかつ5の倍数の場合は"FizzBuzz"を出力
  • それ以外の場合はその数値をそのまま文字列として出力

 とてもシンプルですが、条件分岐などのプログラミング要素が含められているため、しばしばサンプルとして用いられる問題です。今回はFizzBuzz問題のうち、整数値を受け取って、上記の文字列を返す部分をメソッドとして実装し、インテリテストを試してみましょう。

 Visual Studio 2015 Enterpriseを起動して、[新しいプロジェクト]をクリックし、[Visual C#]-[コンソール アプリケーション]を選択して新しいプロジェクトを作成します。作成したプロジェクトに新たなクラスとして「FizzBuzz.cs」を追加し、リスト1のようなコードを入力します。

リスト1 FizzBuzzクラスを追加し、Sayメソッドを実装する(FizzBuzz.cs)
public class FizzBuzz
{
    public string Say(int i)
    {
        //3の倍数でかつ5の倍数の場合は"FizzBuzz"を出力
        if (i % 3 == 0 && i % 5 == 0) return "FizzBuzz";

        //3の倍数の倍数の場合は"Fizz"を出力
        if (i % 3 == 0) return "Fizz";
        
        //5の倍数の場合は"Buzz"を出力
        if (i % 5 == 0) return "Buzz";
        
        //それ以外の場合はその数値をそのまま文字列として出力
        return i.ToString();
    }
}

 コード自体は前述の定義通りなので解説は省略します。なお、インテリテストの対象となるクラスはpublicでなければなりませんので注意してください。例えば、自動的に生成された「Program.cs」のProgramクラスはpublicと宣言されていないので、そのままではインテリテストをかけることができません。テスト対象のメソッドについては、privateなメソッドやstaticなメソッドなども含め、特に条件がないようです。

 では、このメソッドに対してインテリテストをかけてみましょう。メソッド上で右クリックしてコンテキストメニューを出し、[Run InteliTest]を実行します(図6)。

図6 コンテキストメニューから[Run InteliTest]を実行する
図6 コンテキストメニューから[Run InteliTest]を実行する

 少し時間がたった後、画面下の「InteliTest Exploration Results」ペインに図7のような、インテリテストの実行結果が表示されます。注目したいのは表の中の「i」列と「結果」列です。Sayメソッド引数の「int i」に「i」列の値を指定すると、メソッドの戻り値として「結果」列の値が返る、という意味になります。

図7 インテリテストの実行結果
図7 インテリテストの実行結果

 生成されたテストの結果を確認してみると、さまざまな入力値がテストされていることが分かりますが、いくらか想定外の結果も出ています。3の倍数("Fizz"を出力)、5の倍数("Buzz"を出力)、3でも5でも割り切れない場合(数値をそのまま出力)は想定通りの出力が出ていますが、3の倍数かつ5の倍数("FizzBuzz"を出力)のパターンについては、入力値が0となっています。これは、元のFizzBuzz問題では「1から100までの整数について」とあったのに対し、今回のメソッドでは入力値が範囲外の場合もそのまま処理していた、というのが原因です。

 では、仕様を調整してコードを修正しましょう。今回は単純に「1から100の範囲外の値の場合はArgumentExceptionを例外送出する」という仕様にし、リスト2のコードをメソッド先頭に挿入しました。

リスト2 仕様漏れの修正(FizzBuzz.cs)
//1-100範囲外の値の場合はArgumentExceptionを例外送出
if (i < 1 || i > 100) throw new ArgumentException();

 コードを修正したところで、再度インテリテストを実行しましょう。先ほどと同じようにコンテキストメニューから実行しても良いですが、「InteliTest Exploration Results」ペインの[実行]ボタンを押すことでもインテリテストを再生成できます。今度は図8のように想定通りのテストが生成されます。

図8 インテリテストの再実行結果
図8 インテリテストの再実行結果

 なお、インテリテストを実行するたびにテストが再生成されますが、生成されたテストを別のプロジェクトに保存する機能も存在しますので、同じテストに対して再帰テストを行うことも可能です。

 ここでは、1から100の範囲外の数である0に対してはArgumentExceptionが例外送出されることが確認できます。そして、

  • 3の倍数である96の場合:"Fizz"
  • 5の倍数である50の場合:"Buzz"
  • 3の倍数かつ5の倍数である60の場合:"FizzBuzz"
  • それ以外の1、11の場合:そのままの数字

が、それぞれ結果として返ってくることが確認できます。このように、インテリテストを使うことで、テスト対象のメソッドのすべてのコードを網羅するテストが自動生成されます。

 では、FizzBuzzコードをリスト3のように書いてしまうとどうなるでしょうか。

リスト3 コードの順番を間違えた例(FizzBuzz.cs)
public string Say(int i)
{
    //1-100範囲外の値の場合はArgumentExceptionを例外送出
    if (i < 1 || i > 100) throw new ArgumentException();

    //3の倍数の倍数の場合は"Fizz"を出力
    if (i % 3 == 0) return "Fizz";
    
    //5の倍数の場合は"Buzz"を出力
    if (i % 5 == 0) return "Buzz";

    //3の倍数でかつ5の倍数の場合は"FizzBuzz"を出力
    //この順番ではこのコードは実行されない!!! 
    if (i % 3 == 0 && i % 5 == 0) return "FizzBuzz";

    //それ以外の場合はその数値をそのまま文字列として出力
    return i.ToString();
}

 これは仕様通りの順番でコードを記述した結果、"FizzBuzz"を出力する3と5の両方の倍数のパターンが、先に3の倍数である"Fizz"を出力するパターンに飲み込まれて実行されないコードができてしまう、というよくあるミスです。このコードに対してインテリテストをかけた結果は図9のようになります。

図9 問題のあるコードに対するインテリテスト結果
図9 問題のあるコードに対するインテリテスト結果

 テスト自体は問題なく生成されていますが、上の緑のゲージに注目すると、ゲージが満タンになっていないことが確認できます。ゲージの上にマウスオーバーすると図10のようなメッセージが表示され、テストでカバーされていないコードが存在することが分かります。

図10 ゲージのマウスオーバーメッセージ。テストでカバーされていないコードが存在する
図10 ゲージのマウスオーバーメッセージ。テストでカバーされていないコードが存在する

 ゲージの右横の文字列の部分は動的カバレッジ(テスト対象コードのうち、テストでカバーされている網羅率)を表しており、「13/15 ブロック」となっていますので、やはりテストでカバーされていない部分が存在することが分かります。今回は比較的簡単なミスでしたので、インテリテストがなくてもすぐに気づける部分だったかもしれません。しかし、複雑な業務コードにおいて、テストコードの作成が不十分であると、このようなバグになかなか気づくことができない場合がありますので、インテリテストのサポートは有用です。

次のページ
Visual Studio 2015に搭載されたその他のデバッグ便利機能

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
あらゆるソフトウェア開発者のサポートを目指す開発ツール「Visual Studio 2015」特集連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 土井 毅(ドイ ツヨシ)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

【AD】本記事の内容は記事掲載開始時点のものです 企画・制作 株式会社翔泳社

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/8805 2015/07/27 19:03

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング