34

これら 2 つのテストは同じように動作するはずだと思いました。実際、MS Test を使用してプロジェクトでテストを作成したところ、NUnit と同じように期待されるメッセージを尊重していないことがわかりました。

NUnit (失敗):

[Test, ExpectedException(typeof(System.FormatException), ExpectedMessage = "blah")]
public void Validate()
{
    int.Parse("dfd");
}

MS テスト (合格):

[TestMethod, ExpectedException(typeof(System.FormatException), "blah")]
public void Validate()
{
    int.Parse("dfd");
}

ms テストにどんなメッセージを与えても、合格します。

メッセージが正しくない場合に ms テストを失敗させる方法はありますか? 独自の例外属性を作成することはできますか? これが発生するすべてのテストに対して、try catch ブロックを記述する必要はありません。

4

8 に答える 8

30

私たちはこの属性をいたるところで使用していますが、明らかに 2 番目のパラメーターを誤解していました (残念です)。

ただし、例外メッセージを確認するために使用したことは間違いありません。以下は、このページのヒントで使用したものです。グローバリゼーションや継承された例外タイプは処理しませんが、必要なことは実行します。繰り返しますが、目標は単純に 'ExpectedException' を RR して、このクラスと交換することでした。(残念なことに、ExpectedException は封印されています。)

public class ExpectedExceptionWithMessageAttribute : ExpectedExceptionBaseAttribute
{
    public Type ExceptionType { get; set; }

    public string ExpectedMessage { get; set; }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType)
    {
        this.ExceptionType = exceptionType;
    }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage)
    {
        this.ExceptionType = exceptionType;
        this.ExpectedMessage = expectedMessage;
    }

    protected override void Verify(Exception e)
    {
        if (e.GetType() != this.ExceptionType)
        {
            Assert.Fail($"ExpectedExceptionWithMessageAttribute failed. Expected exception type: {this.ExceptionType.FullName}. " +
                $"Actual exception type: {e.GetType().FullName}. Exception message: {e.Message}");
        }

        var actualMessage = e.Message.Trim();
        if (this.ExpectedMessage != null)
        {
            Assert.AreEqual(this.ExpectedMessage, actualMessage);
        }

        Debug.WriteLine($"ExpectedExceptionWithMessageAttribute:{actualMessage}");
    }
}
于 2013-06-05T16:42:21.837 に答える
24

mstest の 2 番目のパラメーターは、テストが失敗したときに出力されるメッセージです。formatexception がスローされた場合、mstest は成功します。役に立つかもしれないこの投稿を見つけました

http://blogs.msdn.com/b/csell/archive/2006/01/13/expectedexception-might-not-be-what-you-ve-expected.aspx

于 2011-01-17T05:39:08.657 に答える
16

@rcravens は正しいです。2 番目のパラメーターは、テストが失敗した場合に出力されるメッセージです。これを回避するために私が行ったことは、テストを少し異なる方法で作成することです。確かに、私はこのアプローチが好きではありませんが、うまくいきます。

[TestMethod]
public void Validate()
{
    try
    {
        int.Parse("dfd");
    
        // Test fails if it makes it this far
        Assert.Fail("Expected exception was not thrown.");
    }
    catch (ArgumentNullException ex) // <-- Expected Exception class
    {
        Assert.AreEqual("blah", ex.Message);
    }
    catch (Exception ex) // All the other exceptions
    {
        Assert.Fail("Thrown exception was of the wrong type");
    }
}
于 2012-05-16T13:57:49.920 に答える
9

含む、大文字と小文字を区別しない、および ResourcesType-ResourceName の組み合わせのサポートを追加することで、プロジェクトの BlackjacketMack からの回答を拡張しました。

使用例:

public class Foo
{
    public void Bar(string mode)
    {
        if (string.IsNullOrEmpty(mode)) throw new InvalidOperationException(Resources.InvalidModeSpecified);
    }

    public void Bar(int port)
    {
        if (port < 0 || port > Int16.MaxValue) throw new ArgumentOutOfRangeException("port");
    }
}

[TestClass]
class ExampleClass
{
    [TestMethod]
    [ExpectedExceptionWithMessage(typeof(InvalidOperationException), typeof(Samples.Resources), "InvalidModeSpecified")]
    public void Raise_Exception_With_Message_Resource()
    {
        new Foo().Bar(null);
    }

    [TestMethod]
    [ExpectedExceptionWithMessage(typeof(ArgumentOutOfRangeException), "port", true)]
    public void Raise_Exeception_Containing_String()
    {
        new Foo().Bar(-123);
    }
}

更新されたクラスは次のとおりです。

public class ExpectedExceptionWithMessageAttribute : ExpectedExceptionBaseAttribute
{
    public Type ExceptionType { get; set; }

    public Type ResourcesType { get; set; }

    public string ResourceName { get; set; }

    public string ExpectedMessage { get; set; }

    public bool Containing { get; set; }

    public bool IgnoreCase { get; set; }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType)
        : this(exceptionType, null)
    {
    }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage)
        : this(exceptionType, expectedMessage, false)
    {
    }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage, bool containing)
    {
        this.ExceptionType = exceptionType;
        this.ExpectedMessage = expectedMessage;
        this.Containing = containing;
    }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType, Type resourcesType, string resourceName)
        : this(exceptionType, resourcesType, resourceName, false)
    {
    }

    public ExpectedExceptionWithMessageAttribute(Type exceptionType, Type resourcesType, string resourceName, bool containing)
    {
        this.ExceptionType = exceptionType;
        this.ExpectedMessage = ExpectedMessage;
        this.ResourcesType = resourcesType;
        this.ResourceName = resourceName;
        this.Containing = containing;
    }

    protected override void Verify(Exception e)
    {
        if (e.GetType() != this.ExceptionType)
        {
            Assert.Fail(String.Format(
                            "ExpectedExceptionWithMessageAttribute failed. Expected exception type: <{0}>. Actual exception type: <{1}>. Exception message: <{2}>",
                            this.ExceptionType.FullName,
                            e.GetType().FullName,
                            e.Message
                            )
                        );
        }

        var actualMessage = e.Message.Trim();

        var expectedMessage = this.ExpectedMessage;

        if (expectedMessage == null)
        {
            if (this.ResourcesType != null && this.ResourceName != null)
            {
                PropertyInfo resourceProperty = this.ResourcesType.GetProperty(this.ResourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
                if (resourceProperty != null)
                {
                    string resourceValue = null;

                    try
                    {
                        resourceValue = resourceProperty.GetMethod.Invoke(null, null) as string;
                    }
                    finally
                    {
                        if (resourceValue != null)
                        {
                            expectedMessage = resourceValue;
                        }
                        else
                        {
                            Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Could not get resource value. ResourceName: <{0}> ResourcesType<{1}>.",
                            this.ResourceName,
                            this.ResourcesType.FullName);
                        }
                    }
                }
                else
                {
                    Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Could not find static resource property on resources type. ResourceName: <{0}> ResourcesType<{1}>.",
                        this.ResourceName,
                        this.ResourcesType.FullName);
                }
            }
            else
            {
                Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Both ResourcesType and ResourceName must be specified.");
            }
        }

        if (expectedMessage != null)
        {
            StringComparison stringComparison = this.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
            if (this.Containing)
            {
                if (actualMessage == null || actualMessage.IndexOf(expectedMessage, stringComparison) == -1)
                {
                    Assert.Fail(String.Format(
                                    "ExpectedExceptionWithMessageAttribute failed. Expected message: <{0}>. Actual message: <{1}>. Exception type: <{2}>",
                                    expectedMessage,
                                    e.Message,
                                    e.GetType().FullName
                                    )
                                );
                }
            }
            else
            {
                if (!string.Equals(expectedMessage, actualMessage, stringComparison))
                {
                    Assert.Fail(String.Format(
                                    "ExpectedExceptionWithMessageAttribute failed. Expected message to contain: <{0}>. Actual message: <{1}>. Exception type: <{2}>",
                                    expectedMessage,
                                    e.Message,
                                    e.GetType().FullName
                                    )
                                );
                }
            }
        }
    }
}
于 2013-09-20T18:35:13.530 に答える
4

この記事で説明されているこのプロジェクトのコードを使用して、MS Test と連携して目的の結果を得る ExpectedExceptionMessage 属性を作成できます。

ミリ秒テスト (失敗):

[TestClass]
public class Tests : MsTestExtensionsTestFixture
{
    [TestMethod, ExpectedExceptionMessage(typeof(System.FormatException), "blah")]
    public void Validate()
    {
        int.Parse("dfd");
    }
}
于 2011-01-18T01:24:29.700 に答える
1

私はこれをしばらく前に書いたので、VS2012 にはもっと良い方法があるかもしれません。

http://dripcode.blogspot.com.au/search?q=例外

于 2013-08-29T03:02:14.220 に答える