カテゴリ: C# 更新日: 2026/04/25

C#のテストで例外を検証する方法を徹底解説!デバッグとエラー対策の基本

C#のテストで例外が発生するケースを検証する方法
C#のテストで例外が発生するケースを検証する方法

先生と生徒の会話形式で理解しよう

生徒

「C#でプログラムを作っているとき、わざとエラーが起きるか確認したい場合はどうすればいいですか?」

先生

「それは例外テストという手法を使います。想定外の入力があったときに、正しくエラーを投げられるかをチェックする大切な作業です。」

生徒

「エラーが起きるのが正解、ということもあるんですね。具体的なやり方を教えてください!」

先生

「もちろんです。テストフレームワークを使って、安全に例外を検証する方法を学んでいきましょう!」

1. 例外とは何かを学ぼう

1. 例外とは何かを学ぼう
1. 例外とは何かを学ぼう

プログラミングの世界では、予期せぬトラブルのことを例外(れいがい)と呼びます。例えば、数字をゼロで割ろうとしたり、存在しないファイルを読み込もうとしたりしたときに、コンピューターは「これ以上処理を続けられません!」と悲鳴をあげます。これが例外が発生した状態です。

初心者のうちは、例外が出ると「失敗した」と思いがちですが、実はそうではありません。プログラムが暴走したり、間違ったデータを保存したりする前に、安全に停止してくれる防御機能なのです。C#では、この例外を意図的に発生させたり、逆に発生することをテストで確認したりすることが非常に重要になります。

2. テストで例外を検証する目的

2. テストで例外を検証する目的
2. テストで例外を検証する目的

なぜ、わざわざエラーが起きることを確認する必要があるのでしょうか。それは、あなたの作ったプログラムが「悪い操作に対して適切に反応できるか」を確かめるためです。これを異常系テストと呼びます。

例えば、銀行の引き出しシステムを想像してください。残高が千円しかないのに、一万円を引き出そうとしたら、システムは「残高不足です」というエラーを出すべきです。もしエラーが出ずに処理が進んでしまったら大変なことになりますよね。このように、「ダメなものはダメ」と正しく判断できているかをチェックするのが、例外の検証作業なのです。

3. ユニットテストの基本準備

3. ユニットテストの基本準備
3. ユニットテストの基本準備

C#でテストを行うには、通常xUnitNUnitといった「テストフレームワーク」という道具を使います。これは、プログラムが正しく動くか自動で判定してくれる便利なツールです。今回は、特によく使われるxUnitというツールを前提に解説します。

テストを書くときは、まず「何をテストするか」を決めます。テストの対象となるメソッド(処理のまとまり)を呼び出し、その結果が自分の予想通りになるかを比較します。例外のテストの場合は、「この命令を実行したら、特定の名前のエラーが発生すること」を予想として設定します。

4. Assert.Throwsを使った基本的な検証

4. Assert.Throwsを使った基本的な検証
4. Assert.Throwsを使った基本的な検証

xUnitで例外を検証する最も一般的な方法は、Assert.Throwsという命令を使うことです。これは「これから実行する処理で、必ずこのエラーを投げなさい」とコンピューターに命令する書き方です。

まずは、簡単な割り算のプログラムを例に見てみましょう。ゼロで割ることは数学的にできないため、エラーが発生するはずです。


using Xunit;

public class MathChecker
{
    public int Divide(int left, int right)
    {
        if (right == 0)
        {
            throw new System.DivideByZeroException("ゼロで割ることはできません");
        }
        return left / right;
    }
}

public class MathTests
{
    [Fact]
    public void ZeroDivisionTest()
    {
        var checker = new MathChecker();
        // 0で割ったときに、DivideByZeroExceptionという例外が発生するか検証します
        Assert.Throws<System.DivideByZeroException>(() => checker.Divide(10, 0));
    }
}

このコードでは、Divideメソッドの引数に「0」を渡したとき、正しくエラーが発生するかをテストしています。もしエラーが起きなければ、このテストは「失敗」となり、プログラムに不備があることがわかります。

5. 例外のメッセージ内容を確認する

5. 例外のメッセージ内容を確認する
5. 例外のメッセージ内容を確認する

ただエラーが出るだけでなく、エラーメッセージの内容が正しいかどうかをチェックしたい場合もあります。例えば「入力が空です」と出るべきなのに「システムエラー」と出たら、利用者は困ってしまいますよね。

Assert.Throwsは、発生した例外そのものを戻り値として返してくれるので、その中身を詳しく調べることが可能です。次の例を見てみましょう。


[Fact]
public void MessageCheckTest()
{
    var checker = new MathChecker();
    
    // 発生した例外を変数「ex」に受け取ります
    var ex = Assert.Throws<System.DivideByZeroException>(() => checker.Divide(10, 0));
    
    // エラーメッセージが期待通りか確認します
    Assert.Equal("ゼロで割ることはできません", ex.Message);
}

このように書くことで、単に種類が合っているかだけでなく、ユーザーに伝える言葉まで正確にテストできるようになります。これを丁寧に行うことで、品質の高いプログラムへと近づきます。

6. 複数の条件で例外をテストする方法

6. 複数の条件で例外をテストする方法
6. 複数の条件で例外をテストする方法

一つの処理に対して、色々なパターンの悪いデータを入れて試したいことがあります。これをデータ駆動テストと言います。C#のテストでは、[Theory][InlineData]という機能を使って、効率よくテストを回せます。

例えば、名前を入力する欄があったとして、「名前が短すぎる場合」や「名前が空っぽの場合」にエラーが出るかまとめて確認してみましょう。


public class UserRegistration
{
    public void Register(string name)
    {
        if (string.IsNullOrEmpty(name))
        {
            throw new System.ArgumentException("名前を入力してください");
        }
        if (name.Length < 2)
        {
            throw new System.ArgumentException("名前は2文字以上にしてください");
        }
    }
}

public class RegistrationTests
{
    [Theory]
    [InlineData(null)] // データが空の場合
    [InlineData("")]   // 空文字の場合
    [InlineData("あ")] // 1文字だけの場合
    public void InvalidNameTest(string targetName)
    {
        var reg = new UserRegistration();
        // どのデータが来ても、ArgumentExceptionが発生することを期待します
        Assert.Throws<System.ArgumentException>(() => reg.Register(targetName));
    }
}

この書き方をすると、一つのテストプログラムで3つのパターンを自動的に実行してくれます。何度も似たようなコードを書かなくて済むので、非常にスマートです。

7. 非同期処理での例外テスト

7. 非同期処理での例外テスト
7. 非同期処理での例外テスト

最近のプログラミングでは、インターネットからデータを取ってくるような、待ち時間が発生する処理(非同期処理)がよく使われます。C#ではasyncawaitというキーワードを使いますが、この場合の例外テストは少しだけ書き方が異なります。

非同期の場合はAssert.ThrowsAsyncという専用の命令を使います。これを知らないと、テストが正しく終わる前に判定が下されてしまい、うまく検証できないので注意しましょう。


public class FileLoader
{
    public async System.Threading.Tasks.Task LoadAsync(string path)
    {
        await System.Threading.Tasks.Task.Delay(10); // 少し待つ処理
        if (path == null)
        {
            throw new System.ArgumentNullException();
        }
    }
}

public class LoaderTests
{
    [Fact]
    public async System.Threading.Tasks.Task AsyncExceptionTest()
    {
        var loader = new FileLoader();
        // 非同期の例外待機には ThrowsAsync を使います
        await Assert.ThrowsAsync<System.ArgumentNullException>(() => loader.LoadAsync(null));
    }
}

普通のテストと似ていますが、awaitを付けることと、ThrowsAsyncを使うことがポイントです。これで最新のプログラム形式にもバッチリ対応できます。

8. デバッグ機能で例外の原因を突き止める

8. デバッグ機能で例外の原因を突き止める
8. デバッグ機能で例外の原因を突き止める

テストで例外が発生することを確認できたら、次は「なぜその例外が起きたのか」を詳しく調べるデバッグの出番です。デバッグとは、プログラムの中身を一行ずつ覗き見して、犯人探しをすることです。

Visual Studioなどの開発ツールには、例外が発生した瞬間にプログラムを一時停止させる機能があります。停止した場所で、その時の変数の値(中身のデータ)をマウスで指し示すと、何が原因でエラーになったのかが一目瞭然です。テストコードを動かしながら、このデバッグ機能を併用することで、バグを修正するスピードが劇的に上がります。

9. 初心者が陥りやすい例外テストの罠

9. 初心者が陥りやすい例外テストの罠
9. 初心者が陥りやすい例外テストの罠

例外のテストを書くときに、一番やってはいけないのが「広すぎる範囲でテストすること」です。例えば、Assert.Throws<Exception>のように、一番大元の大雑把なエラーを指定してしまうと、どんなエラーが起きても合格してしまいます。

「ゼロで割ったエラー」を期待しているのに、「ファイルが見つからないエラー」が起きても合格になってしまったら、それは正しいテストとは言えません。できるだけ具体的で細かいエラーの種類(型)を指定するように心がけましょう。これにより、意図しない場所でバグが起きていることに気づきやすくなります。

10. テストを書く習慣を身につけよう

10. テストを書く習慣を身につけよう
10. テストを書く習慣を身につけよう

プログラミングを始めたばかりの頃は、動くものを作るだけで精一杯かもしれません。しかし、後から「これ、変なデータ入れたら壊れるかな?」と不安になることは多いです。そんなときに、今回学んだ例外テストを一つ書いておくだけで、その不安は解消されます。

プログラムを修正したときに、過去に作った機能が壊れていないか一瞬で確認できるのもテストの魅力です。初心者だからこそ、最初から少しずつテストを書く練習をしてみてください。半年後の自分に感謝されること間違いなしです!

カテゴリの一覧へ
新着記事
New1
C#
C#のメソッドのオーバーロードとは?同名メソッドを複数定義する方法
New2
C#
C#の出力と入力の基本をマスター!初心者でもわかるConsole.WriteLine()とConsole.ReadLine()の使い方
New3
C#
C# GUIアプリでファイルダイアログを使う方法!WinFormsとWPFの基本操作を完全解説
New4
Azure
Azure SQL Databaseの認証設定を徹底解説!Entra ID(旧Azure AD)統合でセキュアなデータベース管理を実現する方法
人気記事
No.1
Java&Spring記事人気No1
C#
C#の日付型(DateTime)と基本的な使い方を解説|初心者向け入門ガイド
No.2
Java&Spring記事人気No2
C#
C#のpartialクラスとは?初心者でも理解できるクラス分割の基本
No.3
Java&Spring記事人気No3
C#
C#でswitch式を使う方法!C# 8.0以降の新機能を解説
No.4
Java&Spring記事人気No4
C#
C# WinForms入門!初心者でも簡単にWindowsアプリを作る方法
No.5
Java&Spring記事人気No5
C#
C#の文字列を数値に変換する方法(int.Parse・TryParse)をわかりやすく解説!
No.6
Java&Spring記事人気No6
C#
C#のログ出力入門!SerilogとNLogの使い方を徹底解説
No.7
Java&Spring記事人気No7
Azure
Azure Bastionの使い方を徹底解説!踏み台サーバー不要で安全にRDP/SSH接続
No.8
Java&Spring記事人気No8
C#
C#のWPFとは?XAMLでGUI開発を基礎から完全解説!初心者向けの入門ガイド