【C#】xUnit.netで値が指定範囲内に収まっているか検証する

目次

概要

xUnit.netの Assert.InRange メソッドを使用して、テスト結果の値が特定の最小値と最大値の範囲内(境界値を含む)にあるかを検証する実装です。 整数だけでなく、日付(DateTime)や浮動小数点数など、IComparable を実装しているすべての型に対して利用可能です。

仕様(入出力)

  • 入力: 検証したい値(Actual)、範囲の最小値(Low)、範囲の最大値(High)
  • 出力: 検証結果
    • 値が Low <= Actual <= High なら成功
    • 範囲外なら Xunit.Sdk.InRangeException が発生しテスト失敗
  • 前提: xunit パッケージがインストールされていること。

基本の使い方

[Fact]
public void CheckScoreRange()
{
    int score = 85;
    
    // 0以上100以下であることを検証
    Assert.InRange(score, 0, 100);
}

コード全文

乱数生成クラスの戻り値が期待される範囲内に収まっているかをテストするコードです。

using System;
using Xunit;

namespace RangeTesting
{
    public class RangeTests
    {
        [Fact]
        public void GetInt_ReturnsValueBetween1And7()
        {
            var obj = new MySampleClass();

            // 乱数なので複数回試行して範囲外が出ないか確認
            for (int i = 0; i < 10; i++)
            {
                var value = obj.GetInt();

                // 値が 1 以上 7 以下であることを検証 (inclusive)
                // Random.Next(1, 8) は 1〜7 を返すため、このテストは常にパスするはず
                Assert.InRange(value, 1, 7);
            }
        }

        [Fact]
        public void StaticValue_IsInRange()
        {
            // 固定値の検証例
            // 1 は 1〜17 の範囲内
            Assert.InRange(1, 1, 17);
        }

        [Fact]
        public void CheckNotInRange()
        {
            int value = 999;
            
            // 範囲「外」であることを検証する場合は NotInRange を使用
            Assert.NotInRange(value, 1, 10);
        }
    }

    /// <summary>
    /// テスト対象のクラス
    /// </summary>
    public class MySampleClass
    {
        private readonly Random _rnd = new Random();

        /// <summary>
        /// 1から7までのランダムな整数を返します
        /// </summary>
        public int GetInt()
        {
            // Next(minValue, maxValue) -> maxValueは排他的(含まれない)
            return _rnd.Next(1, 8); 
        }
    }
}

カスタムポイント

  • 日付の範囲チェック: 数値だけでなく DateTime にも使用できます。C#var dt = new DateTime(2025, 1, 1); Assert.InRange(dt, new DateTime(2024, 1, 1), new DateTime(2025, 12, 31));
  • 境界値の扱い: Assert.InRange は「以上・以下(Inclusive)」です。つまり Assert.InRange(5, 5, 10) は成功します。境界値を含めたくない場合は、テストコード側で値を調整するか、< > 演算子と Assert.True を組み合わせる必要があります。

注意点

  1. 引数の順序: Assert.InRange(actual, low, high) の順序です。第1引数が「検証したい値」です。間違えやすいので注意してください。
  2. IComparableの実装: 自作クラスのインスタンスを範囲チェックしたい場合、そのクラスが IComparable<T> インターフェースを実装している必要があります。
  3. 乱数テストの不確実性: コード例では Random をテストしていますが、実際の単体テストではランダム要素はモック(固定値を返す偽物)に置き換えるのが定石です。ランダムなままテストすると、「たまたま範囲外の値が出た時だけCIが落ちる」という再現性の低いバグ(Flaky Test)の原因になります。

応用

double型の範囲チェック

浮動小数点数の場合も同様に使用できます。

[Fact]
public void Temperature_IsSafe()
{
    double temperature = 36.5;
    
    // 36.0度から37.5度の範囲内か
    Assert.InRange(temperature, 36.0, 37.5);
}

まとめ

Assert.InRange は数値、日付、時間など「大小比較が可能」なあらゆる値に対して有効です。入力値のバリデーションロジックや、計算結果が異常値になっていないかを確認するテストにおいて、Assert.True(val >= min && val <= max) と書くよりも可読性が高く、失敗時に具体的な値が表示されるためデバッグが容易になります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次