在 MSTest 中,如何使用 [ExpectedException(typeof(ApplicationException))] 验证确切的错误消息

发布于 2024-08-15 20:10:24 字数 250 浏览 2 评论 0原文

使用 MSTest 如何验证来自测试方法的确切错误消息?我知道 [ExpectedException(typeof(ApplicationException), error msg)] 不会比较来自我的测试方法的错误消息,尽管在其他单元测试框架中它正在这样做。

解决这个问题的一种方法是使用一些 try catch 块编写单元测试,但我再次需要多编写 4 行。

有没有最聪明的方法来检查错误消息。

干杯, 普里坦

Using MSTest how can I verify the exact error message coming from a test method? I know [ExpectedException(typeof(ApplicationException), error msg)] doesn't compare the error message coming from my test method, though in other unit test framework it is doing.

One way to solve this problem is to write my unit test using some try catch block, but again I need to write 4 lines more.

Is there any smartest way to check the error message.

Cheers,
Pritam

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

揽清风入怀 2024-08-22 20:10:24

您可以创建自己的 ExpectedException 属性您可以在其中断言抛出的异常消息。

代码

namespace TestProject
{
    public sealed class MyExpectedException : ExpectedExceptionBaseAttribute
    {
        private Type _expectedExceptionType;
        private string _expectedExceptionMessage;

        public MyExpectedException(Type expectedExceptionType)
        {
            _expectedExceptionType = expectedExceptionType;
            _expectedExceptionMessage = string.Empty;
        }

        public MyExpectedException(Type expectedExceptionType, string expectedExceptionMessage)
        {
            _expectedExceptionType = expectedExceptionType;
            _expectedExceptionMessage = expectedExceptionMessage;
        }

        protected override void Verify(Exception exception)
        {
            Assert.IsNotNull(exception);

            Assert.IsInstanceOfType(exception, _expectedExceptionType, "Wrong type of exception was thrown.");

            if(!_expectedExceptionMessage.Length.Equals(0))
            {
                Assert.AreEqual(_expectedExceptionMessage, exception.Message, "Wrong exception message was returned.");
            }
        }
    }
}

用法

[TestMethod]
[MyExpectedException(typeof(Exception), "Error")]
public void TestMethod()
{
    throw new Exception("Error");
}

You can create your own ExpectedException attribute where you can Assert the message of the Exception that was thrown.

Code

namespace TestProject
{
    public sealed class MyExpectedException : ExpectedExceptionBaseAttribute
    {
        private Type _expectedExceptionType;
        private string _expectedExceptionMessage;

        public MyExpectedException(Type expectedExceptionType)
        {
            _expectedExceptionType = expectedExceptionType;
            _expectedExceptionMessage = string.Empty;
        }

        public MyExpectedException(Type expectedExceptionType, string expectedExceptionMessage)
        {
            _expectedExceptionType = expectedExceptionType;
            _expectedExceptionMessage = expectedExceptionMessage;
        }

        protected override void Verify(Exception exception)
        {
            Assert.IsNotNull(exception);

            Assert.IsInstanceOfType(exception, _expectedExceptionType, "Wrong type of exception was thrown.");

            if(!_expectedExceptionMessage.Length.Equals(0))
            {
                Assert.AreEqual(_expectedExceptionMessage, exception.Message, "Wrong exception message was returned.");
            }
        }
    }
}

Usage

[TestMethod]
[MyExpectedException(typeof(Exception), "Error")]
public void TestMethod()
{
    throw new Exception("Error");
}
昔日梦未散 2024-08-22 20:10:24

使用这个小帮助器类:

public static class ExceptionAssert
{
    public static void Throws<TException>(Action action, string message)
        where TException : Exception
    {
        try
        {
            action();

            Assert.Fail("Exception of type {0} expected; got none exception", typeof(TException).Name);
        }
        catch (TException ex)
        {
            Assert.AreEqual(message, ex.Message);
        }
        catch (Exception ex)
        {
            Assert.Fail("Exception of type {0} expected; got exception of type {1}", typeof(TException).Name, ex.GetType().Name);               
        }
    }
}

用法:

Foo foo = new Foo();
foo.Property = 42;

ExceptionAssert.Throws<InvalidOperationException>(() => foo.DoSomethingCritical(), "You cannot do anything when Property is 42.");

显式捕获异常的优点是,当另一个成员(例如在初始化期间)抛出异常时,测试不会成功。

Use this little helper class:

public static class ExceptionAssert
{
    public static void Throws<TException>(Action action, string message)
        where TException : Exception
    {
        try
        {
            action();

            Assert.Fail("Exception of type {0} expected; got none exception", typeof(TException).Name);
        }
        catch (TException ex)
        {
            Assert.AreEqual(message, ex.Message);
        }
        catch (Exception ex)
        {
            Assert.Fail("Exception of type {0} expected; got exception of type {1}", typeof(TException).Name, ex.GetType().Name);               
        }
    }
}

Usage:

Foo foo = new Foo();
foo.Property = 42;

ExceptionAssert.Throws<InvalidOperationException>(() => foo.DoSomethingCritical(), "You cannot do anything when Property is 42.");

The advantage of explicit catching exceptions is that teh test does not succeed when another member (e.g. during the initialization) throws the exception.

奢望 2024-08-22 20:10:24

MSTest v2 支持 Assert.Throws 和 Assert.ThrowsAsync,它们返回捕获的异常。

以下是有关如何升级到 MSTest v2 的文章: https://blogs.msdn.microsoft.com/devops/2017/09/01/upgrade-to-mstest-v2/

以下是示例用法:

var myObject = new MyObject();
var ex = Assert.Throws<ArgumentNullException>(() => myObject.Do(null));
StringAssert.Contains(ex.Message, "Parameter name: myArg");

MSTest v2 supports Assert.Throws and Assert.ThrowsAsync which returns the captured exception.

Here is an article on how to upgrade to MSTest v2: https://blogs.msdn.microsoft.com/devops/2017/09/01/upgrade-to-mstest-v2/

Here is example usage:

var myObject = new MyObject();
var ex = Assert.Throws<ArgumentNullException>(() => myObject.Do(null));
StringAssert.Contains(ex.Message, "Parameter name: myArg");
菊凝晚露 2024-08-22 20:10:24

流利断言 (NuGet)具有非常“语言自然”的语法,用于定义单元测试中的期望:

objectundertest.Invoking(o => o.MethodUnderTest()).Should().Throw<ExpectedException>()
    .WithMessage("the expected error message");

使用任何算法检查错误消息都有多种变体(Where(e => ...)以及检查内部异常及其消息。

Fluent Assertions (NuGet) has a very "language natural" syntax for defining expectations in unit tests:

objectundertest.Invoking(o => o.MethodUnderTest()).Should().Throw<ExpectedException>()
    .WithMessage("the expected error message");

There are multiple variations for checking the error message with any algorithm (Where(e => ...) as well as checking into inner exceptions and their messages.

﹏半生如梦愿梦如真 2024-08-22 20:10:24

在 MSTest 中没有内置的方法可以做到这一点。这大约是“优雅”的:

[TestMethod]
public void Test8()
{
    var t = new Thrower();
    try
    {
        t.DoStuffThatThrows();
        Assert.Fail("Exception expected.");
    }
    catch (InvalidOperationException e)
    {
        Assert.AreEqual("Boo hiss!", e.Message);
    }
}

但是,您可以考虑将 xUnit.NET 的 Assert.Throws API 移植到自定义库 - 这就是我们所做的。

您还可以访问 Microsoft Connect 对此建议进行投票

In MSTest there's no built-in way of doing it. This is about as 'elegant' as it gets:

[TestMethod]
public void Test8()
{
    var t = new Thrower();
    try
    {
        t.DoStuffThatThrows();
        Assert.Fail("Exception expected.");
    }
    catch (InvalidOperationException e)
    {
        Assert.AreEqual("Boo hiss!", e.Message);
    }
}

However, you could consider porting xUnit.NET's Assert.Throws API to a custom library - that's what we did.

You could also go to Microsoft Connect an vote on this suggestion.

骄傲 2024-08-22 20:10:24

我正在寻找一种方法来使用 mstest 检查内部异常的存在和类型,我发现了这个问题。我知道这是一个 2 年前的话题,但由于我的解决方案不在这里,让我分享一下。

对我来说,解决问题的最优雅的方法是创建一个派生属性,这是我的(抱歉,注释和字符串是法语,这是我的自然语言,但它应该是显而易见的):

#region Références
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text.RegularExpressions;
#endregion

namespace MsTestEx
{
    /// <summary>
    /// Extention de l'attribut ExpectedException permettant de vérifier plus d'éléments (Message, InnerException, ...)
    /// </summary>
    public class ExpectedExceptionEx
        : ExpectedExceptionBaseAttribute
    {
        #region Variables locales
        private Type    _ExpectedException              = null;
        private string  _ExpectedMessage                = null;
        private Type    _ExpectedInnerException         = null;
        private string  _ExpectedInnerExceptionMessage  = null;
        private bool    _IsExpectedMessageRegex         = false;
        private bool    _IsExpectedInnerMessageRegex    = false;
        private bool    _AllowDerivedType               = false;
        private bool    _AllowInnerExceptionDerivedType = false;

        private bool    _CheckExpectedMessage           = false;
        private bool    _CheckInnerExceptionType        = false;
        private bool    _CheckInnerExceptionMessage     = false;
        #endregion

        #region Propriétés
        /// <summary>
        /// Vérifie que le message de l'exception correspond à celui-ci.
        /// </summary>
        public string ExpectedMessage
        {
            get { return _ExpectedMessage; }
            set { _ExpectedMessage = value; _CheckExpectedMessage = true; }
        }

        /// <summary>
        /// Vérifie que le message de l'inner-exception correspond à celui-ci.
        /// </summary>
        public string ExpectedInnerExceptionMessage
        {
            get { return _ExpectedInnerExceptionMessage; }
            set { _ExpectedInnerExceptionMessage = value; _CheckInnerExceptionMessage = true; }
        }

        /// <summary>
        /// Vérifie que l'exception possède bien une inner-exception du type spécifié.
        /// Spécifier "null" pour vérifier l'absence d'inner-exception.
        /// </summary>
        public Type ExpectedInnerException
        {
            get { return _ExpectedInnerException; }
            set { _ExpectedInnerException = value; _CheckInnerExceptionType = true; }
        }

        /// <summary>
        /// Indique si le message attendu est exprimé via une expression rationnelle.
        /// </summary>
        public bool IsExpectedMessageRegex
        {
            get { return _IsExpectedMessageRegex; }
            set { _IsExpectedMessageRegex = value; }
        }

        /// <summary>
        /// Indique si le message attendu de l'inner-exception est exprimé via une expression rationnelle.
        /// </summary>
        public bool IsExpectedInnerMessageRegex
        {
            get { return _IsExpectedInnerMessageRegex; }
            set { _IsExpectedInnerMessageRegex = value; }
        }

        /// <summary>
        /// Indique si les exceptions dérivées sont acceptées.
        /// </summary>
        public bool AllowDerivedType
        {
            get { return _AllowDerivedType; }
            set { _AllowDerivedType = value; }
        }

        /// <summary>
        /// Indique si les inner-exceptions dérivées sont acceptées.
        /// </summary>
        public bool AllowInnerExceptionDerivedType
        {
            get { return _AllowInnerExceptionDerivedType; }
            set { _AllowInnerExceptionDerivedType = value; }
        }
        #endregion

        #region Constructeurs
        /// <summary>
        /// Indique le type d'exception attendu par le test.
        /// </summary>
        /// <param name="expectedException">Type de l'exception attendu.</param>
        public ExpectedExceptionEx(Type expectedException)
        {
            _ExpectedException = expectedException;
        }
        #endregion

        #region Méthodes
        /// <summary>
        /// Effectue la vérification.
        /// </summary>
        /// <param name="exception">Exception levée.</param>
        protected override void Verify(Exception exception)
        {
            Assert.IsNotNull(exception); // Pas eu d'exception, ce n'est pas normal

            // Vérification du type de l'exception
            Type actualType = exception.GetType();
            if (_AllowDerivedType) Assert.IsTrue(_ExpectedException.IsAssignableFrom(actualType), "L'exception reçue n'est pas du type spécifié ni d'un type dérivé.");
            else Assert.AreEqual(_ExpectedException, actualType, "L'exception reçue n'est pas du type spécifié.");

            // Vérification du message de l'exception
            if (_CheckExpectedMessage)
            {
                if (_IsExpectedMessageRegex)
                    Assert.IsTrue(Regex.IsMatch(exception.Message, _ExpectedMessage), "Le message de l'exception ne correspond pas à l'expression rationnelle");
                else
                {
                    string s1, s2;
                    if (exception.Message.Length > _ExpectedMessage.Length)
                    {
                        s1 = exception.Message;
                        s2 = _ExpectedMessage;
                    }
                    else
                    {
                        s1 = _ExpectedMessage;
                        s2 = exception.Message;
                    }
                    Assert.IsTrue(s1.Contains(s2), "Le message de l'exception ne contient pas et n'est pas contenu par le message attendu.");
                }
            }

            if (_CheckInnerExceptionType)
            {
                if (_ExpectedInnerException == null) Assert.IsNotNull(exception.InnerException);
                else
                {
                    // Vérification du type de l'exception
                    actualType = exception.InnerException.GetType();
                    if (_AllowInnerExceptionDerivedType) Assert.IsTrue(_ExpectedInnerException.IsAssignableFrom(actualType), "L'inner-exception reçue n'est pas du type spécifié ni d'un type dérivé.");
                    else Assert.AreEqual(_ExpectedInnerException, actualType, "L'inner-exception reçue n'est pas du type spécifié.");
                }
            }

            if (_CheckInnerExceptionMessage)
            {
                Assert.IsNotNull(exception.InnerException);
                if (_IsExpectedInnerMessageRegex)
                    Assert.IsTrue(Regex.IsMatch(exception.InnerException.Message, _ExpectedInnerExceptionMessage), "Le message de l'exception ne correspond pas à l'expression rationnelle");
                else
                {
                    string s1, s2;
                    if (exception.InnerException.Message.Length > _ExpectedInnerExceptionMessage.Length)
                    {
                        s1 = exception.InnerException.Message;
                        s2 = _ExpectedInnerExceptionMessage;
                    }
                    else
                    {
                        s1 = _ExpectedInnerExceptionMessage;
                        s2 = exception.InnerException.Message;
                    }
                    Assert.IsTrue(s1.Contains(s2), "Le message de l'inner-exception ne contient pas et n'est pas contenu par le message attendu.");
                }
            }
        }
        #endregion
    }
}

现在,使用带有命名参数的属性“预期异常”。使用我的属性,您可以检查是否存在内部异常、异常消息和内部异常、使用正则表达式来匹配消息等...
您可以根据需要进行调整。

I was looking for a way to check the presence and type of inner exception with mstest and I found this question. I known it a 2 years old topic but since my solution is not here, let me share it.

To me, the most elegant way to solve the problem is to create a derived attribute, here's mine (sorry but comments and strings are in french, my natural language, but it should be obvious) :

#region Références
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text.RegularExpressions;
#endregion

namespace MsTestEx
{
    /// <summary>
    /// Extention de l'attribut ExpectedException permettant de vérifier plus d'éléments (Message, InnerException, ...)
    /// </summary>
    public class ExpectedExceptionEx
        : ExpectedExceptionBaseAttribute
    {
        #region Variables locales
        private Type    _ExpectedException              = null;
        private string  _ExpectedMessage                = null;
        private Type    _ExpectedInnerException         = null;
        private string  _ExpectedInnerExceptionMessage  = null;
        private bool    _IsExpectedMessageRegex         = false;
        private bool    _IsExpectedInnerMessageRegex    = false;
        private bool    _AllowDerivedType               = false;
        private bool    _AllowInnerExceptionDerivedType = false;

        private bool    _CheckExpectedMessage           = false;
        private bool    _CheckInnerExceptionType        = false;
        private bool    _CheckInnerExceptionMessage     = false;
        #endregion

        #region Propriétés
        /// <summary>
        /// Vérifie que le message de l'exception correspond à celui-ci.
        /// </summary>
        public string ExpectedMessage
        {
            get { return _ExpectedMessage; }
            set { _ExpectedMessage = value; _CheckExpectedMessage = true; }
        }

        /// <summary>
        /// Vérifie que le message de l'inner-exception correspond à celui-ci.
        /// </summary>
        public string ExpectedInnerExceptionMessage
        {
            get { return _ExpectedInnerExceptionMessage; }
            set { _ExpectedInnerExceptionMessage = value; _CheckInnerExceptionMessage = true; }
        }

        /// <summary>
        /// Vérifie que l'exception possède bien une inner-exception du type spécifié.
        /// Spécifier "null" pour vérifier l'absence d'inner-exception.
        /// </summary>
        public Type ExpectedInnerException
        {
            get { return _ExpectedInnerException; }
            set { _ExpectedInnerException = value; _CheckInnerExceptionType = true; }
        }

        /// <summary>
        /// Indique si le message attendu est exprimé via une expression rationnelle.
        /// </summary>
        public bool IsExpectedMessageRegex
        {
            get { return _IsExpectedMessageRegex; }
            set { _IsExpectedMessageRegex = value; }
        }

        /// <summary>
        /// Indique si le message attendu de l'inner-exception est exprimé via une expression rationnelle.
        /// </summary>
        public bool IsExpectedInnerMessageRegex
        {
            get { return _IsExpectedInnerMessageRegex; }
            set { _IsExpectedInnerMessageRegex = value; }
        }

        /// <summary>
        /// Indique si les exceptions dérivées sont acceptées.
        /// </summary>
        public bool AllowDerivedType
        {
            get { return _AllowDerivedType; }
            set { _AllowDerivedType = value; }
        }

        /// <summary>
        /// Indique si les inner-exceptions dérivées sont acceptées.
        /// </summary>
        public bool AllowInnerExceptionDerivedType
        {
            get { return _AllowInnerExceptionDerivedType; }
            set { _AllowInnerExceptionDerivedType = value; }
        }
        #endregion

        #region Constructeurs
        /// <summary>
        /// Indique le type d'exception attendu par le test.
        /// </summary>
        /// <param name="expectedException">Type de l'exception attendu.</param>
        public ExpectedExceptionEx(Type expectedException)
        {
            _ExpectedException = expectedException;
        }
        #endregion

        #region Méthodes
        /// <summary>
        /// Effectue la vérification.
        /// </summary>
        /// <param name="exception">Exception levée.</param>
        protected override void Verify(Exception exception)
        {
            Assert.IsNotNull(exception); // Pas eu d'exception, ce n'est pas normal

            // Vérification du type de l'exception
            Type actualType = exception.GetType();
            if (_AllowDerivedType) Assert.IsTrue(_ExpectedException.IsAssignableFrom(actualType), "L'exception reçue n'est pas du type spécifié ni d'un type dérivé.");
            else Assert.AreEqual(_ExpectedException, actualType, "L'exception reçue n'est pas du type spécifié.");

            // Vérification du message de l'exception
            if (_CheckExpectedMessage)
            {
                if (_IsExpectedMessageRegex)
                    Assert.IsTrue(Regex.IsMatch(exception.Message, _ExpectedMessage), "Le message de l'exception ne correspond pas à l'expression rationnelle");
                else
                {
                    string s1, s2;
                    if (exception.Message.Length > _ExpectedMessage.Length)
                    {
                        s1 = exception.Message;
                        s2 = _ExpectedMessage;
                    }
                    else
                    {
                        s1 = _ExpectedMessage;
                        s2 = exception.Message;
                    }
                    Assert.IsTrue(s1.Contains(s2), "Le message de l'exception ne contient pas et n'est pas contenu par le message attendu.");
                }
            }

            if (_CheckInnerExceptionType)
            {
                if (_ExpectedInnerException == null) Assert.IsNotNull(exception.InnerException);
                else
                {
                    // Vérification du type de l'exception
                    actualType = exception.InnerException.GetType();
                    if (_AllowInnerExceptionDerivedType) Assert.IsTrue(_ExpectedInnerException.IsAssignableFrom(actualType), "L'inner-exception reçue n'est pas du type spécifié ni d'un type dérivé.");
                    else Assert.AreEqual(_ExpectedInnerException, actualType, "L'inner-exception reçue n'est pas du type spécifié.");
                }
            }

            if (_CheckInnerExceptionMessage)
            {
                Assert.IsNotNull(exception.InnerException);
                if (_IsExpectedInnerMessageRegex)
                    Assert.IsTrue(Regex.IsMatch(exception.InnerException.Message, _ExpectedInnerExceptionMessage), "Le message de l'exception ne correspond pas à l'expression rationnelle");
                else
                {
                    string s1, s2;
                    if (exception.InnerException.Message.Length > _ExpectedInnerExceptionMessage.Length)
                    {
                        s1 = exception.InnerException.Message;
                        s2 = _ExpectedInnerExceptionMessage;
                    }
                    else
                    {
                        s1 = _ExpectedInnerExceptionMessage;
                        s2 = exception.InnerException.Message;
                    }
                    Assert.IsTrue(s1.Contains(s2), "Le message de l'inner-exception ne contient pas et n'est pas contenu par le message attendu.");
                }
            }
        }
        #endregion
    }
}

Now, use this attribute with named parameters instead of the "ExpectedException". With my attribute you can check if there is an inner exception, message of the exception and inner exception, use a regex to match messages, etc...
You can adapt as you want.

孤檠 2024-08-22 20:10:24

注释和 try/catch 块的烦恼在于,测试的 ACT 和 ASSERT 阶段之间没有明确的分离。一种更简单的方法是使用实​​用程序例程“捕获”异常作为 ACT 阶段的一部分,例如:

public static class Catch
{
    public static Exception Exception(Action action)
    {
        Exception exception = null;

        try
        {
            action();
        }
        catch (Exception ex)
        {
            exception = ex;
        }

        return exception;
    }
}

这允许您执行以下操作:

// ACT
var actualException = Catch.Exception(() => DoSomething())

// ASSERT
Assert.IsNotNull(actualException, "No exception thrown");
Assert.IsInstanceOfType(actualException, expectedType);
Assert.AreEqual(expectedExceptionMessage, actualException.Message);

The annoyance with annotations and try/catch blocks is that you don't have a clean separation between the ACT and ASSERT phases of the test. A simpler appraoch is to "capture" the exception as part of the ACT phase using a utitlity routine such as:

public static class Catch
{
    public static Exception Exception(Action action)
    {
        Exception exception = null;

        try
        {
            action();
        }
        catch (Exception ex)
        {
            exception = ex;
        }

        return exception;
    }
}

This allows you to do:

// ACT
var actualException = Catch.Exception(() => DoSomething())

// ASSERT
Assert.IsNotNull(actualException, "No exception thrown");
Assert.IsInstanceOfType(actualException, expectedType);
Assert.AreEqual(expectedExceptionMessage, actualException.Message);
日裸衫吸 2024-08-22 20:10:24

使用 MSTest,您无法做到这一点。

您已经知道此问题的解决方案:在 catch 块中断言异常消息。

With MSTest, you can't do this.

You already know the solution to this problem: assert the message of an exception in a catch block.

去了角落 2024-08-22 20:10:24

更新:哎呀..看到你想要在 MSTest 中使用它。对不起。速读与被你的标题误导了。

尝试一下 Callum Hibbert 的这个扩展项目看看它是否有效。

旧回复:

您可以使用 NUnit 2.4 及更高版本来执行此操作。
请参阅此处的 ExpectedException 文档

[ExpectedException( typeof( ArgumentException), ExpectedMessage="unspecified", MatchType=MessageMatch.Contains )]
public void TestMethod()
{
...

MatchType 可以是 Exact(默认)、Contains 或 Regex.. 这几乎可以处理 80% 的用例。如果验证变得太复杂,还有一种高级异常处理程序方法。个人从未使用过它。还不需要它。

Update: Oops.. see that you want this in MSTest. Sorry. Speed read & Misled by your title.

Try this extension project from Callum Hibbert and see if it works.

Old response:

You can do this with NUnit 2.4 and above.
See documentation of ExpectedException here

[ExpectedException( typeof( ArgumentException), ExpectedMessage="unspecified", MatchType=MessageMatch.Contains )]
public void TestMethod()
{
...

MatchType can be Exact (default), Contains or Regex.. which pretty much handles the 80% use-case. There is also an advanced exception handler method approach if the verification gets too complex.. never used it personally.. didn't need it yet.

很快妥协 2024-08-22 20:10:24

MbUnit 也可以这样做:

[Test]
[Row(ExpectedExceptionMessage="my message")]
void TestBlah(...

MbUnit can also do this:

[Test]
[Row(ExpectedExceptionMessage="my message")]
void TestBlah(...
奢华的一滴泪 2024-08-22 20:10:24

此代码在异步/等待场景中执行此操作:

代码参考

public async static Task AssertThrowsAsync<T>(Task task, string expectedMessage) where T : Exception
{
    try
    {
        await task;
    }
    catch (Exception ex)
    {
        if (ex is T)
        {
            Assert.AreEqual(expectedMessage, ex.Message);
            return;
        }

        Assert.Fail($"Expection exception type: {typeof(T)} Actual type: {ex.GetType()}");
    }

    Assert.Fail($"No exception thrown");
}

用法示例:
代码参考

    [TestMethod]
    public async Task TestBadRequestThrowsHttpStatusCodeException()
    {
        var mockHttp = new MockHttpMessageHandler();

        const HttpStatusCode statusCode = HttpStatusCode.BadRequest;

        mockHttp.When("https://restcountries.eu/rest/v2/")
                .Respond(statusCode, "application/json", JsonConvert.SerializeObject(new { Message = "Test", ErrorCode = 100 }));

        var httpClient = mockHttp.ToHttpClient();

        var factory = new SingletonHttpClientFactory(httpClient);

        var baseUri = new Uri("https://restcountries.eu/rest/v2/");
        var client = new Client(new NewtonsoftSerializationAdapter(), httpClientFactory: factory, baseUri: baseUri, logger: _logger.Object);

        await AssertThrowsAsync<HttpStatusException>(client.GetAsync<List<RestCountry>>(), Messages.GetErrorMessageNonSuccess((int)statusCode, baseUri));
    }

这是同步情况的等效

public static void AssertThrows<T>(Action action, string expectedMessage) where T : Exception
{
    try
    {
        action.Invoke();
    }
    catch (Exception ex)
    {
        if (ex is T)
        {
            Assert.AreEqual(expectedMessage, ex.Message);
            return;
        }

        Assert.Fail($"Expection exception type: {typeof(T)} Actual type: {ex.GetType()}");
    }

    Assert.Fail($"No exception thrown");
}

注:这断言异常继承自给定类型。如果您想检查特定类型,您应该检查类型相等性,而不是使用 is 运算符。

This code does it in the async/await scenario:

Code Reference

public async static Task AssertThrowsAsync<T>(Task task, string expectedMessage) where T : Exception
{
    try
    {
        await task;
    }
    catch (Exception ex)
    {
        if (ex is T)
        {
            Assert.AreEqual(expectedMessage, ex.Message);
            return;
        }

        Assert.Fail($"Expection exception type: {typeof(T)} Actual type: {ex.GetType()}");
    }

    Assert.Fail($"No exception thrown");
}

Example Usage:
Code Reference

    [TestMethod]
    public async Task TestBadRequestThrowsHttpStatusCodeException()
    {
        var mockHttp = new MockHttpMessageHandler();

        const HttpStatusCode statusCode = HttpStatusCode.BadRequest;

        mockHttp.When("https://restcountries.eu/rest/v2/")
                .Respond(statusCode, "application/json", JsonConvert.SerializeObject(new { Message = "Test", ErrorCode = 100 }));

        var httpClient = mockHttp.ToHttpClient();

        var factory = new SingletonHttpClientFactory(httpClient);

        var baseUri = new Uri("https://restcountries.eu/rest/v2/");
        var client = new Client(new NewtonsoftSerializationAdapter(), httpClientFactory: factory, baseUri: baseUri, logger: _logger.Object);

        await AssertThrowsAsync<HttpStatusException>(client.GetAsync<List<RestCountry>>(), Messages.GetErrorMessageNonSuccess((int)statusCode, baseUri));
    }

This is the equivalent for synchronous situations

public static void AssertThrows<T>(Action action, string expectedMessage) where T : Exception
{
    try
    {
        action.Invoke();
    }
    catch (Exception ex)
    {
        if (ex is T)
        {
            Assert.AreEqual(expectedMessage, ex.Message);
            return;
        }

        Assert.Fail($"Expection exception type: {typeof(T)} Actual type: {ex.GetType()}");
    }

    Assert.Fail($"No exception thrown");
}

Note: this asserts that the exception inherits from a given type. If you want to check for the specific type you should check for Type equality instead of using the is operator.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文