В MSTest, как проверить точное сообщение об ошибке с помощью [ExpectedException (typeof (ApplicationException))]
Использование MSTest, как я могу проверить точное сообщение об ошибке, исходящее из метода тестирования? Я знаю, что [ExpectedException(typeof(ApplicationException), error msg)]
не сравнивает сообщение об ошибке, исходящее из моего тестового метода, хотя в другой структуре unit test он делает.
Один из способов решить эту проблему - написать мой unit test с помощью некоторого блока catch try, но снова мне нужно написать еще 4 строки.
Есть ли лучший способ проверить сообщение об ошибке.
Cheers,
Pritam
Ответы
Ответ 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% -ный прецедент. Существует также метод продвинутого метода обработчика исключений, если проверка становится слишком сложной.. никогда не использовал ее лично.. ей еще не понадобилось.