Как я могу использовать Assert.Throws, чтобы утверждать тип исключения? - PullRequest
213 голосов
/ 22 октября 2009

Как использовать Assert.Throws для подтверждения типа исключения и фактической формулировки сообщения.

Примерно так:

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

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

Ответы [ 7 ]

386 голосов
/ 22 октября 2009

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

Вы также можете использовать свободный API для выполнения этих утверждений:

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

Небольшой совет при утверждении сообщений об исключении - украсить метод теста с помощью SetCultureAttribute, чтобы убедиться, что выброшенное сообщение использует ожидаемую культуру. Это вступает в игру, если вы сохраняете свои сообщения об исключениях в качестве ресурсов для локализации.

24 голосов
/ 23 декабря 2010

Теперь вы можете использовать атрибуты ExpectedException, например,

[Test]
[ExpectedException(typeof(InvalidOperationException), 
 ExpectedMessage="You can't do that!"]
public void MethodA_WithNull_ThrowsInvalidOperationException()
{
    MethodA(null);
}
13 голосов
/ 04 декабря 2013
Assert.That(myTestDelegate, Throws.ArgumentException
    .With.Property("Message").EqualTo("your argument is invalid."));
3 голосов
/ 09 марта 2013

Чтобы расширить ответ персистента и предоставить больше функциональных возможностей 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 голосов
/ 18 января 2019

Это старый, но актуальный вопрос с устаревшими ответами, поэтому я добавляю текущее решение:

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

[TestMethod]
public void ThisWillPassIfExceptionThrown()
{
    Assert.ThrowsException<MyCustomException>(
        () => Test(),
        "You can't do that!");
}

Это работает с using Microsoft.VisualStudio.TestTools.UnitTesting;

2 голосов
/ 02 марта 2011

Прошло много времени с тех пор, как эта проблема поднималась, я понимаю, но недавно я столкнулся с тем же и предлагаю эту функцию для 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/

1 голос
/ 09 февраля 2017

Поскольку меня беспокоит многословие некоторых новых шаблонов 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(() => service.Create(content), "Name already exists");
...