shimapapa.io

.NET,VB,C#,AzureなどMS関連中心の技術ブログ

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

前置き

rikupapa-shima.hatenablog.com

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

https://github.com/nrslib/itddd/blob/master/Layered/SnsApplication.Tests/Users/UserRegisterTest.cs#L52

[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を使うのが良いようです。

docs.microsoft.com

[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の存在自体把握できていませんでした・・・

devblogs.microsoft.com