Подтвердить что ты не робот

В MSTest, как проверить точное сообщение об ошибке с помощью [ExpectedException (typeof (ApplicationException))]

Использование MSTest, как я могу проверить точное сообщение об ошибке, исходящее из метода тестирования? Я знаю, что [ExpectedException(typeof(ApplicationException), error msg)] не сравнивает сообщение об ошибке, исходящее из моего тестового метода, хотя в другой структуре unit test он делает.

Один из способов решить эту проблему - написать мой unit test с помощью некоторого блока catch try, но снова мне нужно написать еще 4 строки.

Есть ли лучший способ проверить сообщение об ошибке.

Cheers, Pritam

4b9b3361

Ответ 1

Вы можете создать свой собственный атрибут ExpectedException, где вы можете Assert отправить сообщение Exception.

код

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");
}

Ответ 2

Используйте этот небольшой вспомогательный класс:

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.");

Преимущество явных исключений catching заключается в том, что тест не выполняется, когда другой элемент (например, во время инициализации) генерирует исключение.

Ответ 3

Я искал способ проверить наличие и тип внутреннего исключения с помощью 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
    }
}

Теперь используйте этот атрибут с именованными параметрами вместо "ExpectedException". С моим атрибутом вы можете проверить, есть ли внутреннее исключение, сообщение исключения и внутреннего исключения, используйте регулярное выражение для соответствия сообщениям и т.д.... Вы можете адаптироваться по своему усмотрению.

Ответ 4

В 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 голосовать за это предложение.

Ответ 5

"Свободные утверждения" (доступно в NuGet) имеет очень "языковой естественный" синтаксис для определения ожиданий в модульных тестах:

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

Существует несколько вариантов проверки сообщения об ошибке с любым алгоритмом (Where(e => ...), а также проверка внутренних исключений и их сообщений.

Ответ 6

С MSTest вы не можете этого сделать.

Вы уже знаете решение этой проблемы: утвердите сообщение об исключении в блоке catch.

Ответ 7

MbUnit также может сделать это:

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

Ответ 8

Обновление: К сожалению.. см., что вы хотите это в MSTest. Сожалею. Скорость чтения и ошибки в вашем названии.

Попробуйте этот проект расширения от Callum Hibbert и посмотрите, работает ли он.

Старый ответ:

Вы можете сделать это с помощью NUnit 2.4 и выше. См. документация ExpectedException здесь

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

MatchType может быть Exact (по умолчанию), Contains или Regex.., который в значительной степени обрабатывает 80% -ный прецедент. Существует также метод продвинутого метода обработчика исключений, если проверка становится слишком сложной.. никогда не использовал ее лично.. ей еще не понадобилось.