3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

NCrunchでC#のライブユニットテストを試してみた

3
Posted at

概要

この記事では、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 は、以下のサイトからダウンロードできます。

http://www.ncrunch.net/

まず、Download NCrunch をクリックします。
お使いのバージョンの Visual Studio の Download Installer をクリックすると、インストーラがダウンロードされます。

Visual Studio が起動している場合は終了してから、ダウンロードしたインストーラを実行し、NCrunch をインストールします。

NCrunch の起動

Visual Studio を起動したら、画面上部のメニューバーに「NCRUNCH」が追加されています。「Enable NCrunch」をクリックすると、NCrunch が起動します。ウィザード形式で質問されることがありますが、すべてデフォルト値のまま先に進んで構いません。

NCrunchMenu.png

作成するプログラム

いわゆる 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 プロジェクトを作成します。
コンソールアプリケーションとして作成します。

CreateMyProgram.png

InternalsVisibleTo の設定

MyProgram が、単体テストプロジェクトから見えるように、設定が必要です。
Properties の中にある AssemblyInfo.cs の末尾に、以下の行を追加します。

[assembly: InternalsVisibleTo("MyProgramTest")]

スタブの作成

FizzBuzz メソッドのスタブを作成します。。
以下のコードを、Program.csMyProgram クラスに追加します。

/// <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 のタスク一覧で、まとめて確認することができます。

TaskList.png

詳細は、MSDNの以下のページを参照してください。

ドキュメント コメント用の推奨タグ(C# プログラミング ガイド)

方法: タスク一覧のコメントを作成する

単体テストプロジェクトの作成

作業中のソリューションに、単体テストプロジェクトを追加します。
ソリューション MyProgram を右クリックし、「追加」→「新しいプロジェクト」をクリックします。
名前を MyProgramTest とし、単体テストプロジェクトを作成します。

NewProject.png

NewProject2.png

ユニットテストクラスの作成

MyProgramTest プロジェクトに UnitTest1.cs が作成されているので、FizzBuzzTest.cs にリネームします。

参照の追加

ユニットテストプロジェクトから MyProgram が見えるように、設定が必要です。

MyProgramTest の参照設定を右クリックし、参照の追加をクリックします。MyProgram にチェックを入れ、OKボタンをクリックします。

AddReference.png

テストメソッドの追加

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のライブユニットテストによって付与されたマークです。

  • 赤丸: テストに失敗している
  • 緑丸: テストに合格している
  • 黒丸: テストされていない

FizzBuzz_Failed.png

return "Fizz"; の行の赤丸をクリックしてみましょう。
当該行に関連するテストが、ポップアップで一覧表示されます。赤いバツ印の付いているテストが、失敗しています。

  • 3の倍数かつ5の倍数: テストに失敗している
  • 自然数でない数: テストに失敗している
  • 3の倍数: テストに合格している

ShowTestsCoveringThisLine.png

また、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();
}

修正が終わると、エディタの左側の丸が、すべて緑色になりました。これで、用意したテストに、すべて合格しました。

FizzBuzz_Passed.png

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 ファイルを動かしてみましょう。

CmdExec.png

3
5
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
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?