C#のMSTest使い方を完全解説!単体テストの自動化でバグを防ぐ
生徒
「プログラムを書いた後、正しく動くか一々手動で確認するのが大変です。何か良い方法はありますか?」
先生
「それは大変ですね。C#にはMSTestという仕組みがあって、プログラムが正しいかを自動でチェックできるんですよ。」
生徒
「自動でチェック!それならミスも減りそうですね。初心者でも使えますか?」
先生
「もちろんです。Visual Studioに最初から入っている標準のツールなので、準備も簡単です。一緒に使い方を学びましょう!」
1. MSTestとは?テストを自動化するメリット
MSTest(エムエステスト)とは、マイクロソフトが提供しているC#向けの単体テストフレームワークです。フレームワークとは、特定の作業を効率よく行うための「テンプレート」や「道具箱」のようなものだと考えてください。プログラミングにおける「テスト」とは、作成した機能が設計通りに動くかを確認する作業のことです。
パソコンを触り始めたばかりの方は、プログラムを動かして画面の結果を目で確認していると思います。しかし、プログラムが大きくなると、一箇所を直しただけで別の場所が壊れてしまうことがあります。これを防ぐために、あらかじめ「この命令に5を入れたら10が返ってくるはず」という正解を登録しておき、ボタン一つで全ての機能が正しいか検証するのが自動テストの役割です。
MSTestはVisual Studioに標準搭載されているため、追加のインストール作業が少なく、初心者にとって最も導入しやすいテストツールと言えます。バグを早期発見し、高品質なプログラムを作るためには欠かせない知識です。
2. テストプロジェクトの作成方法と準備
C#でテストを始めるには、普段コードを書いているプロジェクトとは別に、テスト専用のプロジェクトを作る必要があります。これを「テストプロジェクト」と呼びます。料理に例えると、料理を作るキッチン(メインプロジェクト)とは別に、味見をするための専用の小部屋(テストプロジェクト)を作るようなイメージです。
Visual Studioを開き、「新しいプロジェクトの作成」から「MSTest」と検索してください。すると「MSTest テスト プロジェクト」という項目が出てきます。これを選択して作成することで、テストに必要な設定が自動的に行われた状態からスタートできます。プロジェクト名には、元のプロジェクト名に「.Tests」と付けるのが一般的なルールです。例えば、本体が「MyApp」なら「MyApp.Tests」とします。
次に、テストしたい本体のプロジェクトをテストプロジェクトから参照できるように設定します。これにより、テストプロジェクト側から本体のプログラムを呼び出せるようになります。この設定を忘れると、テストコードを書いても「そんな名前のプログラムは見つかりません」というエラーが出てしまうので注意しましょう。
3. 最初に覚える3つの重要な属性
MSTestには、普通のプログラムと区別するための「属性(属性ラベル)」という特別な印があります。これを使うことで、Visual Studioに対して「これはテスト用のクラスですよ」「これは実行するテストメソッドですよ」と教えることができます。主に使うのは以下の3つです。
- TestClass(テストクラス):テストコードが書かれているクラスの先頭に付けます。
- TestMethod(テストメソッド):実際にテストを行う命令のまとまりの先頭に付けます。
- Assert(アサート):予想した結果と実際の結果が一致しているかを確認する命令です。
それでは、まずは非常にシンプルな足し算のプログラムをテストする例を見てみましょう。まずは計算を行うためのクラスを作成します。
// 計算を担当するシンプルなクラス
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
}
このプログラムが正しく動くかを確認するためのテストコードを次に書きます。[TestClass]や[TestMethod]という記述に注目してください。角括弧で囲まれたこれらの記述が、MSTestを動かすためのスイッチになります。
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class CalculatorTests
{
[TestMethod]
public void Add_2と3を足したら5になること()
{
// 1. 準備(Arrange):テストしたいクラスを用意する
var calc = new Calculator();
// 2. 実行(Act):実際に計算させる
int result = calc.Add(2, 3);
// 3. 検証(Assert):結果が5であることを確認する
Assert.AreEqual(5, result);
}
}
実行結果は、Visual Studioの「テストエクスプローラー」という画面で確認できます。成功すると緑色のチェックマークが表示されます。
テストの実行に成功しました: Add_2と3を足したら5になること
4. Assertクラスの主要なメソッド
テストの肝となるのが、結果を検証するAssertクラスです。Assertは日本語で「断言する」という意味があります。「この結果は絶対こうなるはずだ!」とプログラムに言い聞かせる役割です。よく使われる命令を紹介します。
Assert.AreEqual(期待値, 実際値):二つの値が等しいかどうかを調べます。最も頻繁に使う命令です。例えば、会員登録後のユーザー名が入力したものと一致するかなどをチェックします。
Assert.IsTrue(条件):括弧の中の条件が正しい(真)かどうかを調べます。例えば、「年齢が20歳以上であるか」という判定が正しいかをチェックする時に便利です。
Assert.IsNotNull(対象):中身が空っぽ(null)ではないことを調べます。データがちゃんと読み込めているかを確認するのに使います。逆に空っぽであることを確認するAssert.IsNullもあります。
これらの命令を使い分けることで、複雑なプログラムの動作も細かくチェックできるようになります。次のコード例では、文字列の判定を行うテストを見てみましょう。
[TestClass]
public class StringTest
{
[TestMethod]
public void 文字列の結合テスト()
{
string firstName = "田中";
string lastName = "太郎";
string fullName = firstName + lastName;
// 文字列が一致するか検証
Assert.AreEqual("田中太郎", fullName);
// 文字列が空ではないことを検証
Assert.IsNotNull(fullName);
}
}
5. テストを整理するための初期化と後処理
たくさんのテストを書いていると、毎回同じ準備作業(データの読み込みやクラスの作成)が必要になることがあります。毎回同じコードを書くのは面倒ですし、間違いの元です。そこでMSTestには、テストの前後に自動で実行される便利な仕組みが用意されています。
TestInitialize(テストイニシャライズ):各テストメソッドが実行される直前に必ず動く処理です。共通の準備コードをここに書きます。例えば、データベースへの接続準備や、テスト用ファイルの作成などを行います。
TestCleanup(テストクリーンアップ):各テストが終わった直後に必ず動く処理です。テストで使ったゴミを片付けるために使います。例えば、一時的に作ったファイルを削除したり、メモリを解放したりします。
これらを使うことで、一つひとつのテストコードを短く、読みやすく保つことができます。初心者の方は、まず「準備」と「片付け」という専用の場所があることだけ覚えておけば大丈夫です。以下に、リスト(データの集まり)を使った例を紹介します。
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class ListTests
{
private List<string> _list;
[TestInitialize]
public void Setup()
{
// テストごとに新しくリストを作る
_list = new List<string>();
}
[TestMethod]
public void リストにデータを追加できること()
{
_list.Add("りんご");
Assert.AreEqual(1, _list.Count);
}
[TestMethod]
public void リストの最初の要素が正しいこと()
{
_list.Add("ばなな");
Assert.AreEqual("ばなな", _list[0]);
}
}
6. 意図的にエラーを起こす例外テスト
プログラムのテストでは、正しく動くことだけでなく、「おかしなデータが入った時に正しくエラーが出るか」を確認することも非常に重要です。これを例外テストと呼びます。例えば、マイナスの年齢が入力されたときに、プログラムが黙って進むのではなく「それはおかしいですよ!」とエラー(例外)を投げるように作ることがあります。
MSTestでは、ExpectedExceptionという属性を使って、「このテストはエラーが出るのが正解です」という指定ができます。エラーが出れば合格、エラーが出ずに最後まで動いてしまったら不合格という逆転の発想でテストを行います。
最近の書き方では、Assert.ThrowsExceptionという命令を使うのが主流です。これにより、特定の処理で特定のエラーが発生することを精密にチェックできます。初心者のうちは少し難しく感じるかもしれませんが、安全なアプリを作るためには避けて通れない大切なステップです。
[TestClass]
public class ExceptionTests
{
[TestMethod]
public void ゼロで割り算をするとエラーになること()
{
int a = 10;
int b = 0;
// 0で割った時に DivideByZeroException というエラーが出るか検証
Assert.ThrowsException<System.DivideByZeroException>(() =>
{
int result = a / b;
});
}
}
7. テストエクスプローラーでの確認とデバッグ
テストコードを書き終えたら、次は実行です。Visual Studioの上部メニューにある「テスト」から「すべてのテストを実行」をクリックします。すると「テストエクスプローラー」というパネルが開き、現在のテスト状況が一覧表示されます。ここで大切なのが「色」の意味を理解することです。
- 緑色のチェック:テスト合格です!期待通りの動作をしています。
- 赤色のバツ:テスト失敗です。どこかにバグがあるか、期待値が間違っています。
- 青色や灰色の記号:まだ実行されていないか、スキップされたテストです。
もし赤色になった場合は、詳細メッセージを確認しましょう。「5を期待していましたが、実際は10でした」といったヒントが表示されます。また、テストコードの左側にマウスを置くと「デバッグ」という選択肢が出ます。これを使うと、プログラムを一行ずつ止めながら動かし、どこで計算が狂ったのかを詳しく調べることができます。テストとデバッグは、二人三脚でバグを退治する最強の武器なのです。
8. 良いユニットテストを書くためのポイント
最後に、初心者の方がテストを書く時に意識してほしいコツを紹介します。テストはただ書けば良いというわけではなく、メンテナンスしやすい(後で読み返した時に分かりやすい)ことが重要です。
一つ目は、一つのテストメソッドで検証することは一つに絞ることです。一つのメソッドであれもこれもチェックしてしまうと、失敗した時にどこが原因か分かりにくくなります。「足し算のテスト」「引き算のテスト」のように、細かく分けて名前を付けましょう。名前は日本語でも英語でも構いませんが、内容が一目でわかる名前にするのがベストです。
二つ目は、テストが他のテストに依存しないようにすることです。Aというテストを実行した後にしかBが動かない、といった状態は避けましょう。それぞれのテストは独立して、どの順番で実行しても同じ結果になるように作るのが基本です。そのためにも、先ほど紹介したTestInitializeなどを活用して、常に真っさらな状態からテストが始まるように工夫してください。これらを意識するだけで、あなたのプログラムの信頼性は飛躍的に向上します。