概要
この記事では、C# での FizzBuzz っぽいプログラム作成を通じて、NCrunch でライブユニットテストを試してみました。
対象読者
- C# を使っている人
- 簡単なコンソールアプリケーションを書き始め、入門書を一通り読んだぐらいのレベルの人
- テスト駆動開発を、ほんの少しだけかじってみたい人
- ライブユニットテストを使いたいけれど、諸事情で Visual Studio 2017 Enterprise を使わせてもらえない人
実行環境
- OS: Windows 7 Pro SP1 64bit(8や10でもOK)
- IDE: Visual Studio Professional 2013 (NCrunchが動作するバージョンならOK)
- NCrunch: NCrunch 3.6
ライブユニットテストについて
ライブユニットテストとは、コードを書きながら、リアルタイムで単体テストが走り、結果を教えてくれるものです。Visual Studio 2017 Enterprise に搭載されて話題になったようです。
Microsoft、Visual Studio 2017にライブユニットテストを提供(InfoQ)
使いこなせると非常に便利なのですが、予算の都合などで、Enterprise 版の Visual Studio を使えない人も多いかと思います。比較的安価なものとして、NCrunch というプラグインで、同様のことができるそうです。
事前準備
NCrunch のインストール
2017年4月現在、このツールは有料で、個人ライセンスが 159米ドル(1ドル110円として、17,490円)です。
企業向けライセンスは 289米ドル(同じく、31,790円)です。
30日の体験版があります。英語のツールですが、簡単な単語しか出てこないので安心してください。
NCrunch は、以下のサイトからダウンロードできます。
まず、Download NCrunch をクリックします。
お使いのバージョンの Visual Studio の Download Installer をクリックすると、インストーラがダウンロードされます。
Visual Studio が起動している場合は終了してから、ダウンロードしたインストーラを実行し、NCrunch をインストールします。
NCrunch の起動
Visual Studio を起動したら、画面上部のメニューバーに「NCRUNCH」が追加されています。「Enable NCrunch」をクリックすると、NCrunch が起動します。ウィザード形式で質問されることがありますが、すべてデフォルト値のまま先に進んで構いません。
作成するプログラム
いわゆる FizzBuzz のプログラムを作成します。
今回は、Wikipedia の例とは異なり、入力した値に対応した文字列を出力するプログラムとします。
また、負の数はすべて、入力値をそのまま文字列にします。
C:\> MyProgram.exe
整数を入力: 3
Fizz
C:\> MyProgram.exe
整数を入力: 5
Buzz
C:\> MyProgram.exe
整数を入力: 15
FizzBuzz
C:\> MyProgram.exe
整数を入力: 17
17
C:\> MyProgram.exe
整数を入力: -3
-3
C:\>
コンソールアプリケーションの作成
ツールバーの「新しいプロジェクト」をクリックし、MyProgram
プロジェクトを作成します。
コンソールアプリケーションとして作成します。
InternalsVisibleTo の設定
MyProgram
が、単体テストプロジェクトから見えるように、設定が必要です。
Properties
の中にある AssemblyInfo.cs
の末尾に、以下の行を追加します。
[assembly: InternalsVisibleTo("MyProgramTest")]
スタブの作成
FizzBuzz メソッドのスタブを作成します。。
以下のコードを、Program.cs
の MyProgram
クラスに追加します。
/// <summary>
/// いわゆるFizzBuzzプログラムです。
/// 3の倍数のときは"Fizz"、5の倍数のときは"Buzz"、両方に該当するときは"FizzBuzz"を出力します。
/// 負の数や、どちらにも該当しないときは、与えられた数字を文字列として出力します。
/// </summary>
/// <param name="number">判定する数字</param>
/// <returns>FizzBuzzの出力を文字列で返します。</returns>
internal static string FizzBuzz(int number)
{
// TODO: スタブ
return null;
}
ここで、先頭にスラッシュ3個のコメントや、XMLのタグがあります。
これは、ドキュメントコメントといいます。
ソースコードをツールに通すと、HTMLなどの形式で、ドキュメントが自動生成されます。
また、先頭に TODO
と書かれたコメントがあります。
TODO コメントは、Visual Studio のタスク一覧で、まとめて確認することができます。
詳細は、MSDNの以下のページを参照してください。
ドキュメント コメント用の推奨タグ(C# プログラミング ガイド)
単体テストプロジェクトの作成
作業中のソリューションに、単体テストプロジェクトを追加します。
ソリューション MyProgram
を右クリックし、「追加」→「新しいプロジェクト」をクリックします。
名前を MyProgramTest
とし、単体テストプロジェクトを作成します。
ユニットテストクラスの作成
MyProgramTest
プロジェクトに UnitTest1.cs
が作成されているので、FizzBuzzTest.cs
にリネームします。
参照の追加
ユニットテストプロジェクトから MyProgram
が見えるように、設定が必要です。
MyProgramTest
の参照設定を右クリックし、参照の追加をクリックします。MyProgram
にチェックを入れ、OKボタンをクリックします。
テストメソッドの追加
FizzBuzzTest.cs
に、テストを記述していきます。
今回作成するプログラムのテストとして、以下のようなケースが考えられます。
- 3の倍数だが、5の倍数でない
- 5の倍数だが、3の倍数でない
- 3の倍数かつ5の倍数
- 3の倍数でも5の倍数でもない
上記に加えて、以下のようなテストケースも考えられます。
- 0の場合
- 負の数の場合
- 整数でない場合(今回は引数が int 型なので考えません)
上記のケースを、テストコードとして実装していきます。
- テスト用のメソッドには、先頭に
[TestMethod]
をつけます。 -
Assert.AreEqual(string expected, string actual)
は、2つの引数が等しいかどうかをテストします。条件に合致しない場合、実行が止まり、そのテストは失敗となります。- 第1引数: 仕様で想定している出力結果
- 第2引数: テスト対象プログラムの実行結果
- メソッド内のすべてのAssertを通過すれば、そのテストは合格となります。
- Assert 系メソッドは、他にも種類があります。詳細は、MSDNの Assert クラス を参照してください。
// FizzBuzzTest.cs
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MyProgram;
namespace MyProgramTest
{
[TestClass]
public class FizzBuzzTest
{
/// <summary>
/// 3の倍数のテストです。
/// </summary>
[TestMethod]
public void TestFizzBuzz_3()
{
Assert.AreEqual("Fizz", Program.FizzBuzz(3));
Assert.AreEqual("Fizz", Program.FizzBuzz(6));
}
/// <summary>
/// 5の倍数のテストです。
/// </summary>
[TestMethod]
public void TestFizzBuzz_5()
{
Assert.AreEqual("Buzz", Program.FizzBuzz(5));
Assert.AreEqual("Buzz", Program.FizzBuzz(10));
}
/// <summary>
/// 3の倍数かつ5の倍数のテストです。
/// </summary>
[TestMethod]
public void TestFizzBuzz_Both()
{
Assert.AreEqual("FizzBuzz", Program.FizzBuzz(15));
Assert.AreEqual("FizzBuzz", Program.FizzBuzz(30));
}
/// <summary>
/// 3の倍数でも5の倍数でもない数のテストです。
/// </summary>
[TestMethod]
public void TestFizzBuzz_OtherNaturalNumber()
{
Assert.AreEqual("2", Program.FizzBuzz(2));
Assert.AreEqual("7", Program.FizzBuzz(7));
}
/// <summary>
/// 自然数でない数(0、負数)のテストです。
/// </summary>
[TestMethod]
public void TestFizzBuzz_NotNaturalNumber()
{
Assert.AreEqual("0", Program.FizzBuzz(0));
Assert.AreEqual("-1", Program.FizzBuzz(-1));
Assert.AreEqual("-3", Program.FizzBuzz(-3));
Assert.AreEqual("-5", Program.FizzBuzz(-5));
Assert.AreEqual("-15", Program.FizzBuzz(-15));
}
}
}
なお、1つのテストメソッド内に、複数のAssertを記述することについては、賛否両論あります。
今回は簡単な例なので、複数記述しています。
FizzBuzz メソッドを実装する
それでは、MyProgram
プロジェクトに戻り、スタブにしておいた FizzBuzz メソッドを実装してみましょう。
タスク一覧の TODO コメントをダブルクリックして、ジャンプすることもできます。
※このコードは、ユニットテストのデモのため、わざと間違えています。
/// <summary>
/// いわゆるFizzBuzzプログラムです。
/// 3の倍数のときは"Fizz"、5の倍数のときは"Buzz"、両方に該当するときは"FizzBuzz"を出力します。
/// どちらにも該当しないときは、与えられた数字を文字列として出力します。
/// </summary>
/// <param name="number">判定する数字</param>
/// <returns>FizzBuzzの出力を文字列で返します。</returns>
internal static string FizzBuzz(int number)
{
if (number % 3 == 0)
{
return "Fizz";
}
else if (number % 5 == 0)
{
return "Buzz";
}
else if (number % 3 == 0 && number % 5 == 0)
{
return "FizzBuzz";
}
else
{
return number.ToString();
}
}
コードを入力すると、エディタの左側に赤、緑、黒の丸印が表示されています。
これは、NCrunchのライブユニットテストによって付与されたマークです。
- 赤丸: テストに失敗している
- 緑丸: テストに合格している
- 黒丸: テストされていない
return "Fizz";
の行の赤丸をクリックしてみましょう。
当該行に関連するテストが、ポップアップで一覧表示されます。赤いバツ印の付いているテストが、失敗しています。
- 3の倍数かつ5の倍数: テストに失敗している
- 自然数でない数: テストに失敗している
- 3の倍数: テストに合格している
また、return "FizzBuzz";
の行は、黒丸がついています。
これは、この行に到達できるテストコードが存在しないことを意味しています。
「3の倍数かつ5の倍数のテスト」は用意しているのに、テストが走っていない。意図した動作ではないので、これもバグということになります。
FizzBuzz メソッドを修正する
それでは、FizzBuzzメソッドを修正していきます。
修正作業中も、リアルタイムにテストが走り、エディタ左側の丸が更新されていきます。
最終的に、以下のコードになるように修正してみましょう。
/// <summary>
/// いわゆるFizzBuzzプログラムです。
/// 3の倍数のときは"Fizz"、5の倍数のときは"Buzz"、両方に該当するときは"FizzBuzz"を出力します。
/// 負の数や、どちらにも該当しないときは、与えられた数字を文字列として出力します。
/// </summary>
/// <param name="number">判定する数字</param>
/// <returns>FizzBuzzの出力を文字列で返します。</returns>
internal static string FizzBuzz(int number)
{
if (number < 3)
{
// 何もせず if を抜けます
}
else if (number % 3 == 0 && number % 5 == 0)
{
return "FizzBuzz";
}
else if (number % 3 == 0)
{
return "Fizz";
}
else if (number % 5 == 0)
{
return "Buzz";
}
return number.ToString();
}
修正が終わると、エディタの左側の丸が、すべて緑色になりました。これで、用意したテストに、すべて合格しました。
Main メソッドの実装
無事にテストを通過し、FizzBuzz
メソッドが完成しました。
次は、Main
メソッドを実装し、コンソールアプリケーションとして動作するようにします。
なお、Main
メソッドの単体テストは割愛します。
/// <summary>
/// FizzBuzzコンソールアプリケーションです。
/// </summary>
/// <param name="args">コマンドライン引数(使用せず)</param>
static void Main(string[] args)
{
while (true)
{
try
{
Console.Write("整数を入力: ");
Console.WriteLine(FizzBuzz(Int32.Parse(Console.ReadLine())));
break;
}
catch (OverflowException)
{
Console.WriteLine("エラー: 数値が大きすぎます。");
continue;
}
catch (Exception)
{
Console.WriteLine("エラー: 整数ではありません。");
continue;
}
}
}
終わったら、ビルドして、できあがった exe ファイルを動かしてみましょう。