What is it, naokirin?

テスト駆動開発の練習(7) -C#&NUnitでインデクサを使ってみる-

今回はC#NUnitでTDDをしつつ、インデクサを使ってコードを書いてみることにしました。

インデクサとは、クラスに配列のように[]でアクセスすることができるようにするプロパティです。うーん、説明下手でスミマセン。インデクサの詳しい説明は他のサイトに任せるとして、今日はC#NUnitを使ってみます。

ちなみに今回、テーマが決まらずに++C++;// 未確認飛行 Cのコードを参考にさせていただいています。ちょっと変えて、上限のみ設定できるようにしています…そのせいでほぼ、ただの配列になってます。そのため、配列の平均と合計を計算するようにしてみました。はっきり言って蛇足です。

class UpperBoundArray
{
    int[] array;
    int upper;

    public UpperBoundArray(int upper)
    {
        this.upper = upper;
        array = new int[upper + 1];
    }

    public int this[int i]
    {
        set { this.array[i] = value; }
        get { return this.array[i]; }
    }

    public double average()
    {
        return sum() / upper;
    }

    public int sum()
    {
        int s = 0;
        foreach (int i in array)
            s += i;
        return s;
    }
}

UpperBoundArray.cs

using System;
using NUnit.Framework;

[TestFixture]
class BoundArrayTest
{
    private UpperBoundArray bA;

    [TestFixtureSetUp]
    public void testFixtureSetUp()
    {
        bA = new UpperBoundArray(4);
        for (int i = 0; i <= 4; i++)
            bA[i] = i;
    }

    [Test]
    public void testIndexer()
    {
        Assert.That(bA[0], Is.EqualTo(0));
        Assert.That(bA[1], Is.EqualTo(1));
        Assert.That(bA[2], Is.EqualTo(2));
        Assert.That(bA[3], Is.EqualTo(3));
        Assert.That(bA[4], Is.EqualTo(4));
    }

    [Test]
    [ExpectedException(typeof(IndexOutOfRangeException))]
    public void testIndexerOutOfRangeException()
    {
        bA[5] = 5;
    }

    [Test]
    public void testAverage()
    {
        Assert.That(bA.average(), Is.EqualTo(2));
    }

    [Test]
    public void testSum()
    {
        Assert.That(bA.sum(), Is.EqualTo(10));
    }
}

UpperBoundArrayTest.cs

初めて例外のテストをしてみました。今回は配列が境界の外を参照したときに発生する例外(IndexOutOfRangeException)をテストしています。他の言語でも例外のテストを触ってみたいですね。


追記:友人に指摘されたので、テストコードをちょっとリファクタリングしてみます。テストコードでインデクサのアクセスをテストしている部分ですが、属性[TestCase]を使うことでコードの重複を抑えられます。

/* 上のtestIndexer()と同じテストを実行 */
[TestCase(0, 0)]
[TestCase(1, 1)]
[TestCase(2, 2)]
[TestCase(3, 3)]
[TestCase(4, 4)]
public void testIndexer(int input, int expected)
{
   Assert.That(bA[input], Is.EqualTo(expected));
}


こうすることで、テストコードの重複を抑えることができます。(今回で言うとAssert.That()の繰り返し)。また、視覚的に入力値と期待値が見えるという効果も期待できます。

まだまだ勉強中なので、こうした「最適なコード」へと自分の書くコードを昇華することができるように努力していきたいと思います。