Как я могу использовать Assert, чтобы проверить, что было сгенерировано исключение? - PullRequest
751 голосов
/ 01 июня 2009

Как мне использовать Assert (или другой класс Test?), Чтобы проверить, что было сгенерировано исключение?

Ответы [ 22 ]

891 голосов
/ 01 июня 2009

Похоже, что для «Visual Studio Team Test» вы применяете атрибут ExpectedException к методу теста.

Пример из документации здесь: Пошаговое руководство по модульному тестированию с Visual Studio Team Test

[TestMethod]
[ExpectedException(typeof(ArgumentException),
    "A userId of null was inappropriately allowed.")]
public void NullUserIdInConstructor()
{
   LogonInfo logonInfo = new LogonInfo(null, "P@ss0word");
}
232 голосов
/ 01 июня 2009

Обычно ваш тестовый фреймворк будет иметь ответ на этот вопрос. Но если он недостаточно гибок, вы всегда можете сделать это:

try {
    somethingThatShouldThrowAnException();
    Assert.Fail(); // If it gets to this line, no exception was thrown
} catch (GoodException) { }

Как указывает @Jonas, это НЕ работает для ловли базового исключения:

try {
    somethingThatShouldThrowAnException();
    Assert.Fail(); // raises AssertionException
} catch (Exception) {
    // Catches the assertion exception, and the test passes
}

Если вам абсолютно необходимо поймать Exception, вам нужно сбросить Assert.Fail (). Но на самом деле, это признак того, что вы не должны писать это от руки; проверьте свои тестовые рамки на наличие вариантов или посмотрите, можете ли вы выдать более значимое исключение для проверки.

catch (AssertionException) { throw; }

Вы должны быть в состоянии адаптировать этот подход к тому, что вам нравится, включая указание, какие исключения нужно ловить. Если вы ожидаете только определенные типы, закончите блоки catch с:

} catch (GoodException) {
} catch (Exception) {
    // not the right kind of exception
    Assert.Fail();
}
106 голосов
/ 12 апреля 2011

Мой предпочтительный метод для реализации этого - написать метод Throws и использовать его, как и любой другой метод Assert. К сожалению, .NET не позволяет вам писать метод статического расширения, поэтому вы не можете использовать этот метод, как если бы он действительно принадлежал сборке в классе Assert; просто сделайте другой под названием MyAssert или что-то подобное. Класс выглядит так:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YourProject.Tests
{
    public static class MyAssert
    {
        public static void Throws<T>( Action func ) where T : Exception
        {
            var exceptionThrown = false;
            try
            {
                func.Invoke();
            }
            catch ( T )
            {
                exceptionThrown = true;
            }

            if ( !exceptionThrown )
            {
                throw new AssertFailedException(
                    String.Format("An exception of type {0} was expected, but not thrown", typeof(T))
                    );
            }
        }
    }
}

Это означает, что ваш юнит-тест выглядит так:

[TestMethod()]
public void ExceptionTest()
{
    String testStr = null;
    MyAssert.Throws<NullReferenceException>(() => testStr.ToUpper());
}

Который выглядит и ведет себя намного больше, чем остальные ваши синтаксисы модульных тестов.

59 голосов
/ 01 июня 2009

Если вы используете MSTest, который изначально не имел атрибута ExpectedException, вы можете сделать это:

try 
{
    SomeExceptionThrowingMethod()
    Assert.Fail("no exception thrown");
}
catch (Exception ex)
{
    Assert.IsTrue(ex is SpecificExceptionType);
}
47 голосов
/ 04 декабря 2013

если вы используете NUNIT, вы можете сделать что-то вроде этого:

Assert.Throws<ExpectedException>(() => methodToTest());


Также возможно сохранить выброшенное исключение для дальнейшей его проверки:

ExpectedException ex = Assert.Throws<ExpectedException>(() => methodToTest());
Assert.AreEqual( "Expected message text.", ex.Message );
Assert.AreEqual( 5, ex.SomeNumber);

См .: http://nunit.org/docs/2.5/exceptionAsserts.html

35 голосов
/ 01 июня 2009

Остерегайтесь использования ExpectedException, так как это может привести к нескольким подводным камням, как показано здесь:

http://geekswithblogs.net/sdorman/archive/2009/01/17/unit-testing-and-expected-exceptions.aspx

А здесь:

http://xunit.github.io/docs/comparisons.html

Если вам нужно проверить исключения, есть и другие, которые не одобряются. Вы можете использовать метод try {act / fail} catch {assert}, который может быть полезен для платформ, которые не имеют прямой поддержки для тестов исключений, кроме ExpectedException.

Лучшей альтернативой является использование xUnit.NET, которая является очень современной, ориентированной на будущее и расширяемой структурой модульного тестирования, которая извлекла уроки из всех других ошибок и усовершенствована. Одним из таких улучшений является Assert.Throws, который обеспечивает гораздо лучший синтаксис для утверждения исключений.

Вы можете найти xUnit.NET на github: http://xunit.github.io/

24 голосов
/ 02 октября 2010

В проекте, над которым я работаю, у нас есть другое решение, которое делает это.

Во-первых, мне не нравится атрибут ExpectedExceptionAttribute, поскольку он учитывает, какой вызов метода вызвал исключение.

Я делаю это с помощью вспомогательного метода.

Test

[TestMethod]
public void AccountRepository_ThrowsExceptionIfFileisCorrupt()
{
     var file = File.Create("Accounts.bin");
     file.WriteByte(1);
     file.Close();

     IAccountRepository repo = new FileAccountRepository();
     TestHelpers.AssertThrows<SerializationException>(()=>repo.GetAll());            
}

HelperMethod

public static TException AssertThrows<TException>(Action action) where TException : Exception
    {
        try
        {
            action();
        }
        catch (TException ex)
        {
            return ex;
        }
        Assert.Fail("Expected exception was not thrown");

        return null;
    }

Аккуратно, не правда ли;)

16 голосов
/ 18 октября 2016

MSTest (v2) теперь имеет функцию Assert.ThrowsException, которую можно использовать следующим образом:

Assert.ThrowsException<System.FormatException>(() =>
            {
                Story actual = PersonalSite.Services.Content.ExtractHeader(String.Empty);
            }); 

Вы можете установить его с помощью nuget: Install-Package MSTest.TestFramework

15 голосов
/ 01 июня 2009

Это атрибут метода тестирования ... вы не используете Assert. Выглядит так:

[ExpectedException(typeof(ExceptionType))]
public void YourMethod_should_throw_exception()
13 голосов
/ 08 апреля 2015

Вы можете загрузить пакет из Nuget, используя: PM> Install-Package MSTestExtensions , который добавляет Assert.Throws () в стиле nUnit / xUnit для MsTest.

Инструкции высокого уровня: загрузите сборку и наследуйте от BaseTest , и вы можете использовать синтаксис Assert.Throws () .

Основной метод для реализации Throws выглядит следующим образом:

public static void Throws<T>(Action task, string expectedMessage, ExceptionMessageCompareOptions options) where T : Exception
{
    try
    {
        task();
    }
    catch (Exception ex)
    {
        AssertExceptionType<T>(ex);
        AssertExceptionMessage(ex, expectedMessage, options);
        return;
    }

    if (typeof(T).Equals(new Exception().GetType()))
    {
        Assert.Fail("Expected exception but no exception was thrown.");
    }
    else
    {
        Assert.Fail(string.Format("Expected exception of type {0} but no exception was thrown.", typeof(T)));
    }
}

Раскрытие: я собрал этот пакет.

Подробнее: http://www.bradoncode.com/blog/2012/01/asserting-exceptions-in-mstest-with.html

...