Assert.Throwsを使用して例外のタイプをアサートするにはどうすればよいですか?


246

Assert.Throws例外のタイプと実際のメッセージの表現をアサートするにはどうすればよいですか。

このようなもの:

Assert.Throws<Exception>(
    ()=>user.MakeUserActive()).WithMessage("Actual exception message")

私がテストしているメソッドは、異なるタイプの同じタイプの複数のメッセージをスローし、コンテキストに応じて正しいメッセージがスローされることをテストする方法が必要です。

回答:


443

Assert.Throws スローされた例外を返し、例外をアサートできます。

var ex = Assert.Throws<Exception>(() => user.MakeUserActive());
Assert.That(ex.Message, Is.EqualTo("Actual exception message"));

したがって、例外がスローされない場合、または間違ったタイプの例外がスローされる場合、最初のAssert.Throwsアサーションは失敗します。ただし、正しいタイプの例外がスローされた場合は、変数に保存した実際の例外をアサートできます。

このパターンを使用することで、例外メッセージ以外のものでアサートできます。たとえば、ArgumentExceptionおよび派生物の場合、パラメーター名が正しいことをアサートできます。

var ex = Assert.Throws<ArgumentNullException>(() => foo.Bar(null));
Assert.That(ex.ParamName, Is.EqualTo("bar"));

これらのアサートを実行するためにFluent APIを使用することもできます。

Assert.That(() => foo.Bar(null), 
Throws.Exception
  .TypeOf<ArgumentNullException>()
  .With.Property("ParamName")
  .EqualTo("bar"));

または代わりに

Assert.That(
    Assert.Throws<ArgumentNullException>(() =>
        foo.Bar(null)
    .ParamName,
Is.EqualTo("bar"));

例外メッセージをアサートするときの小さなヒントは、テストメソッドをで装飾SetCultureAttributeして、スローされたメッセージが期待されるカルチャを使用していることを確認することです。これは、ローカリゼーションを可能にするリソースとして例外メッセージを保存する場合に役立ちます。


これは私にとって非常に役に立ちました。エラーを表示する方法が必要でした。Assert.Throwsメソッドによって値が返された場合でも読みませんでした。ありがとう
Haroon

6
+1 Fluent APIを表示していただきありがとうございます。なんらかの理由で、NUnitドキュメントだけからの使い方の理解に問題がありました。
aolszowka 2013年

メッセージをアサートする場合は、「プロパティ」の代わりにメッセージプロパティを直接使用することもできます。
マルセル

25

これで、ExpectedException属性を使用できるようになります。

[Test]
[ExpectedException(typeof(InvalidOperationException), 
 ExpectedMessage="You can't do that!"]
public void MethodA_WithNull_ThrowsInvalidOperationException()
{
    MethodA(null);
}

2
これは、最初に見たとき、私に少し混乱をもたらしました。テストの見かけには断定がなかったので、それは私にはにおいでした。これは素晴らしい機能ですが、この属性がアサートで使用されるかどうかをチームで話し合う必要があります。スロー
マルセル

14
+1は、例外をテストするための良い方法でもあります。これについて覚えておくべき唯一のことは、理論的には、そのメッセージでInvalidOperationExceptionをスローするコード行がテストに合格するということです。テストデータ/オブジェクトを準備するテスト内のコードや、テストに関心のある1つで、誤検出が発生する可能性があります。もちろん、それはメッセージの具体性とテストする例外のタイプに依存します。ではAssert.Throw、あなたが正確なラインをターゲットにすることができに興味があります。
いや

21
ExpectedException属性はNUnit 3で廃止予定です: github.com/nunit/docs/wiki/Breaking-Changes
FrankSebastiàJun

13
Assert.That(myTestDelegate, Throws.ArgumentException
    .With.Property("Message").EqualTo("your argument is invalid."));

2
:がNameOf演算子の導入により、私はこの優れたanwserを編集しますAssert.That(myTestDelegate, Throws.ArgumentException .With.Property(nameof(ArgumentException.Message)).EqualTo("your argument is invalid."));
サミュエル・

@Samuelその編集は、強く型付けされた参照を使用しますが、一方で、非常にチャーンが少ないプロパティ名であり、魔法の文字列が流暢さを向上させます。好みの問題
ジョーダンモリス

1
に関して、私は完全に同意しますException.MessageWith.Property他のオブジェクトにも利用できるので、少なくともこの代替案を追加することをお勧めします。他のオブジェクトにも利用できるため、この場合はコードの安定性が向上します。
サミュエル

5

これは古くて関連性のある質問で、回答が古いため、現在の解決策を追加します。

public void Test() {
    throw new MyCustomException("You can't do that!");
}

[TestMethod]
public void ThisWillPassIfExceptionThrown()
{
    var exception = Assert.ThrowsException<MyCustomException>(
        () => Test(),
        "This should have thrown!");
    Assert.AreEqual("You can't do that!", exception.Message);
}

これは using Microsoft.VisualStudio.TestTools.UnitTesting;


JUnitのようにメソッドが例外をスローすることを断言する簡潔な方法がないことに本当に驚きました。私が知らない含意がない限り、これはおそらく現在最も関連性の高い答えです。
NetherGranite

3

永続的な答えを拡張し、NUnitの機能をさらに提供するには、次のようにします。

public bool AssertThrows<TException>(
    Action action,
    Func<TException, bool> exceptionCondition = null)
    where TException : Exception 
{
    try
    {
        action();
    }
    catch (TException ex)
    {
        if (exceptionCondition != null)
        {
            return exceptionCondition(ex);
        }

        return true;
    }
    catch
    {
        return false;
    }

    return false; 
}

例:

// No exception thrown - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => {}));

// Wrong exception thrown - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new ApplicationException(); }));

// Correct exception thrown - test passes.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException(); }));

// Correct exception thrown, but wrong message - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException("ABCD"); },
        ex => ex.Message == "1234"));

// Correct exception thrown, with correct message - test passes.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException("1234"); },
        ex => ex.Message == "1234"));

2

この問題が提起されてから久しぶりですが、最近同じことに遭遇し、MSTestにこの関数を提案しました。

public bool AssertThrows(Action action) where T : Exception 
{ 
try {action();} 
catch(Exception exception) 
{ 
    if (exception.GetType() == typeof(T)) return true; 
} 
return false; 
}

使用法:

Assert.IsTrue(AssertThrows<FormatException>(delegate{ newMyMethod(MyParameter); }));

詳細:http : //phejndorf.wordpress.com/2011/02/21/assert-that-a-particular-exception-has-occured/


2

新しいNUnitパターンの冗長性に悩まされているので、次のようなものを使用して、個人的にクリーンなコードを作成します。

public void AssertBusinessRuleException(TestDelegate code, string expectedMessage)
{
    var ex = Assert.Throws<BusinessRuleException>(code);
    Assert.AreEqual(ex.Message, expectedMessage);
}

public void AssertException<T>(TestDelegate code, string expectedMessage) where T:Exception
{
    var ex = Assert.Throws<T>(code);
    Assert.AreEqual(ex.Message, expectedMessage);
}

次に、使用方法は次のとおりです。

AssertBusinessRuleException(() => user.MakeUserActive(), "Actual exception message");

1
TestDelegateとは何ですか?
reggaeguitar

1
パラメータとして実行するコードを渡すことができます。NUnitフレームワーク(v3.2.0.0)のクラスです。
サベージ、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.