【MSTest】Assert.ThrowsExceptionを使用した例外のテスト


※ 個人blogに投稿した記事(投稿日:2020/3/29)をQiitaに移行しました

前置き

ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本」のサンプルコード内で、 以下のようなテストコードを見かけました。

[TestMethod]
public void TestInvalidUserNameLengthMin()
{
    var userFactory = new InMemoryUserFactory();
    var userRepository = new InMemoryUserRepository();
    var userService = new UserService(userRepository);
    var userApplicationService = new UserApplicationService(userFactory, userRepository, userService);
    bool exceptionOccured = false;
    try
    {
        var command = new UserRegisterCommand("12");
        userApplicationService.Register(command);
    }
    catch
    {
        exceptionOccured = true;
    }
    Assert.IsTrue(exceptionOccured);
}

UserRegisterCommand内でユーザー名が3文字以上で無い場合ArgumentExceptionが発生することを検証するテストコードです。
上記のコードでは、例外が発生する箇所をtry〜catchで補足し検証する形式とされています。

MSTestで例外をテストする(ExpectedExceptionAttribute)

前述のテストコードを見たときに、MSTestで例外をアサーションする場合、ExpectedExceptionAttributeを使用するパターンも考えられるのではと感じました。

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void TestInvalidUserNameLengthMin_old()
{
    var userFactory = new InMemoryUserFactory();
    var userRepository = new InMemoryUserRepository();
    var userService = new UserService(userRepository);
    var userApplicationService = new UserApplicationService(userFactory, userRepository, userService);
    var command = new UserRegisterCommand("12");
    userApplicationService.Register(command);
}

MSTestで例外をテストする(Assert.ThrowsException)

最新のMSTestのバージョンではAssert.ThrowsExceptionを使うのが良いようです。

[TestMethod]
public void TestInvalidUserNameLengthMin()
{
   var userFactory = new InMemoryUserFactory();
   var userRepository = new InMemoryUserRepository();
   var userService = new UserService(userRepository);
   var userApplicationService = new UserApplicationService(userFactory, userRepository, userService);
   var ex = Assert.ThrowsException<ArgumentException>(() => 
        {
            var command = new UserRegisterCommand("12");
            userApplicationService.Register(command);
        }
    );
    Assert.AreEqual("ユーザ名は3文字以上です。 (Parameter 'value')", ex.Message);
}

アノテーションよりもAssert.ThrowsExceptionの方が、例外が発生する箇所も明確になるし、発生したexceptionを更に検証できるのも良いですね。
Assert.ThrowsExceptionはVS2017の時代にリリースされた「MSTest v2」で追加された機能のようです。
そもそもMSTest v2の存在自体把握できていませんでした・・・