シナプス技術者ブログ

シナプスの技術者公式ブログ。インターネットで、鹿児島の毎日を笑顔にします。

初めての単体テスト

シナプスの技術部システム開発課の小園です。

単体テスト(ユニットテスト)を初めてみようという方向けの記事です。
C# と NUnit3 の環境で行いました。

単体テスト(ユニットテスト)とは

Wikipedia 単体テスト のページには、以下のように記載されています。

ソースコードの個々のユニット、すなわち、1つ以上のコンピュータプログラムモジュールが使用に適しているかどうかを決定するために、関連する制御データ、使用手順、操作手順とともにテストする手法

出典元:Wikipedia 単体テストhttps://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%93%E3%83%86%E3%82%B9%E3%83%88

単体テストは、個々のユニットの機能が正しく実装されているかを検証するテストです。

単体テストのフレームワーク

マイクロソフト公式ドキュメント .NET Core と .NET Standard の単体テスト には、以下の3製品が紹介されていました。

今回は、この中からNUnitを使って、単体テストをしてみたいと思います。

環境

次の環境で作業しました。

Visual Studio は Enterprise を使っていますが、他のエディション(Professional or Community)でも同じです。

拡張機能のインストール

拡張機能 Test Generator NUnit extension をインストールします。
Visual Studo を起動して、メニューの[拡張機能] > [拡張機能の管理] と進み、Test Generator NUnit extension を検索してインストールします。

f:id:oceandepthz:20200522135440p:plain

テストを書く

テストするクラスを用意

今回は、基準となる日の翌平日を求めるクラスを作成します。
翌平日と書きましたが、面倒なので、祝日は無視しています。
翌平日を求めるメソッド GetNextWeekday はまだ実装していません。

using System;

namespace Example
{
    class Weekday
    {
        private readonly DateTime _referenceDate;

        public Weekday(DateTime referenceDate)
        {
            _referenceDate = referenceDate;
        }

        public DateTime GetNextWeekday()
        {
            throw new NotImplementedException();
        }
    }
}

ユニットテスト雛形を用意

テストしたいクラスの中で右クリックをして「単体テストの作成」をクリックします。

f:id:oceandepthz:20200522160909p:plain

単体テストの作成画面になるので、そのまま[OK]を押します。
テストフレームワークとして、今回はNUnit3を選択します。

f:id:oceandepthz:20200522141241p:plain

テストクラスの雛形が作成されます。
作成されたコードは以下です。

using NUnit.Framework;
using Example;
using System;
using System.Collections.Generic;
using System.Text;

namespace Example.Tests
{
    [TestFixture()]
    public class WeekdayTests
    {
        [Test()]
        public void WeekdayTest()
        {
            Assert.Fail();
        }

        [Test()]
        public void GetNextWeekdayTest()
        {
            Assert.Fail();
        }
    }
}

作成されたプロジェクトの依存関係は以下のようになります。
必要なパッケージがインストールされた状態になります。

f:id:oceandepthz:20200522161103p:plain

インストールされるパッケージのバージョンが若干古い場合がありますので、必要に応じて更新をしてください。

ユニットテストを作成

先に作成したテストクラスを修正して、翌平日が返される仕様を期待するコードを記述します。

using NUnit.Framework;
using System;

namespace Example.Tests
{
    [TestFixture()]
    public class WeekdayTests
    {
        [Test()]
        [TestCase("2020/05/14", "2020/05/15")]
        [TestCase("2020/05/15", "2020/05/18")]
        [TestCase("2020/05/16", "2020/05/18")]
        [TestCase("2020/05/17", "2020/05/18")]
        [TestCase("2020/05/18", "2020/05/19")]
        public void GetNextWeekdayTest(DateTime referenceDate, DateTime expectDate)
        {
            var target = new Weekday(referenceDate);
            var value = target.GetNextWeekday();
            Assert.That(value, Is.EqualTo(expectDate));
        }
    }
}

テストがエラーになる事を確認

メニューの [表示] > [テスト エクスプローラー] を選択し、[すべてのテストを実行] を押します。
全てのテストが例外(NotImplementedException)でエラーになる事を確認します。

f:id:oceandepthz:20200522162628p:plain

機能の実装

翌平日を返す機能を実装します。

using System;

namespace Example
{
    public class Weekday
    {
        private readonly DateTime _referenceDate;

        public Weekday(DateTime referenceDate)
        {
            _referenceDate = referenceDate;
        }

        public DateTime GetNextWeekday()
        {
            if(_referenceDate.DayOfWeek == DayOfWeek.Friday)
            {
                return _referenceDate.AddDays(3);
            }
            if(_referenceDate.DayOfWeek == DayOfWeek.Saturday)
            {
                return _referenceDate.AddDays(2);
            }
            return _referenceDate.AddDays(1);
        }
    }
}

テストが正常に終了する事を確認

テスト エクスプローラーから実行し、全てのテストが正常に終了する事を確認します。

f:id:oceandepthz:20200522163121p:plain

まとめ

今回は、ユニットテストを始める事を目的に記事を作成しました。
サンプルのように依存の無いコードの場合には楽ですが、正しいテストクラスを書く技術や、テストコードを書きやすい設計をする技術、APIなど外部依存している場合にDI(Dependency Injection)等の技術を用いる方法など、まだまだ学ぶべき事は多いと、この記事を作成しながら改めて実感しました。