Як мені перевірити “не сталося винятків” у моєму модульному тесті MSTest?


88

Я пишу одиничний тест для цього методу, який повертає "void". Я хотів би мати один випадок, коли тест проходить, коли немає виключення. Як написати це на C #?

Assert.IsTrue(????)

(Я думаю, це те, як я повинен перевірити, але що входить у "???")

Сподіваюся, моє запитання досить чітке.


Ви використовуєте MSTest або NUnit?
Matt Grande

2
У MSTest незахоплені винятки автоматично спричиняють невдачу тестів. Ви намагаєтесь врахувати спіймані винятки?
Філ

Ви можете знайти "спробувати зловити для C #", і це дасть вам вказівки щодо того, як обробляти викиди, які викидаються чи не видаються.
Фоггзі,

1
Якщо NUnit, подивіться на Assert.That (лямбда) .Бросає.Нічого (хоча, я думаю, це нещодавно змінилося)
Matt Grande

Відповіді:


138

Ваш модульний тест у будь-якому випадку провалиться, якщо буде видано виняток - вам не потрібно вводити спеціальне твердження.

Це один з небагатьох сценаріїв, коли ви побачите модульні тести без жодних тверджень - тест неявно провалиться, якщо буде створено виняток.

Однак, якщо ви дійсно хотіли написати твердження щодо цього - можливо, щоб мати змогу вловити виняток і повідомити "не очікувалося винятків, але отримано це ...", ви можете зробити це:

[Test]
public void TestNoExceptionIsThrownByMethodUnderTest()
{
    var myObject = new MyObject();

    try
    {
        myObject.MethodUnderTest();
    }
    catch (Exception ex)
    {
        Assert.Fail("Expected no exception, but got: " + ex.Message);
    }
}

(вище наведено приклад для NUnit, але те саме справедливо і для MSTest)


Очевидно, що вам не слід їхати та ловити такі винятки, щоб це справді справді.
Серві

7
Тест провалиться, лише якщо буде викинуто невпійманий виняток. Залежно від коду в обробниках винятків, модульні тести можуть пройти.
їстівний код

1
Це корисно для пані Unittest, тому в Unittest немає методу Assert.DoesNotThrow (().
Başar Kaya

25

У NUnit ви можете використовувати:

Assert.DoesNotThrow(<expression>); 

стверджувати, що ваш код не створює винятку. Незважаючи на те, що тест не вдасться, якщо буде створено виняток, навіть якщо навколо нього не буде Assert, цінність цього підходу полягає в тому, що ви можете тоді розрізняти незадоволені очікування та помилки у своїх тестах, і у вас є можливість додати власне повідомлення, яке відображатиметься у результатах тесту. Добре сформульований тестовий результат може допомогти вам знайти помилки у коді, які спричинили невдалий тест.

Я думаю, що доречно додавати тести, щоб переконатися, що ваш код не створює винятків; наприклад, уявіть, що ви перевіряєте введення і вам потрібно перетворити вхідний рядок у довгий. Можуть бути випадки, коли рядок є нульовим, і це прийнятно, тому ви хочете переконатися, що перетворення рядка не створює винятку. Тому для цього випадку буде код, і якщо ви не написали тест для нього, вам не вистачить інформації про важливу частину логіки.


1
Явний DoesNotThrow приємний. Якщо ви звикли бачити Assert. * У тесті, ви можете подумати, що інший хлопець був лінивим і забув.
Метт Бекман,

Чи є для нього еквівалент у vstest або mstest?
Ден Чшарстер

1
@DanCsharpster, я не думаю, що такого є, принаймні в MSTest - коли мені раніше потрібна була ця функція в MSTest, я зробив щось подібне: public class TestBase { //believe me, I don't like this anymore than you do. protected void AssertDoesNotThrow(Action action, string message) { try { action(); } catch (Exception) { Assert.Fail(message); } } }
Clarkeye

@Clarkeye, це цікава ідея. Дякую! Сподіваємось, вони навчаться краще копіювати NUnit у наступних версіях. Я також думав про те, щоб написати адаптер між vstest та NUnit.
Dan Csharpster

@DanCsharpster, одна річ, на яку ти, можливо, захочеш поглянути, - це вільні твердження, які мають приємну підтримку ShouldThrow і ShouldNotThrow: github.com/dennisdoomen/fluentassertions/wiki#exceptions . Документи кажуть, що він сумісний з MSTest (хоча я використовував його лише з XUnit та NUnit). Можливо, ви робите не все, що завгодно, але ви все одно можете змішати це з твердженнями MSTest.
Clarkeye

11

Не перевіряйте, що щось не відбувається . Це як запевнити, що код не зламається . Це начебто мається на увазі, що ми всі прагнемо коду без помилок, без помилок. Ви хочете написати тести для цього? Чому лише один метод? Хіба ви не хочете, щоб усі ваші методи перевірялися, щоб вони не створювали якихось винятків ? Пройшовши цю дорогу, ви отримаєте один додатковий, фіктивний, беззаперечний тест для кожного методу у вашій основі коду. Це не приносить ніякої цінності.

Звичайно, якщо ваша вимога полягає в тому, щоб перевірити метод , уловлюють винятки , ви робите тест , що (або реверсування його трохи, тест , що він не кидає , що він повинен зловити).

Однак загальний підхід / практика залишаються незмінними - ви не пишете тести на деякі штучні / розмиті вимоги, які виходять за межі тестованого коду (а тестування на те, що "це працює" чи "не кидає", як правило, є прикладом такі - особливо в тому випадку, коли обов'язки методу добре відомі).

Якщо сказати простіше - зосередьтеся на тому, що має робити ваш код , і протестуйте це.


10
-1 Я можу думати про позитивні функціональні можливості, які вимагають, а виняток не слід кидати. Для одного методу, завданням якого є обробка винятків, реєстрація їх та вжиття заходів - не кидаючи виняток далі. Ви висловлюєте добру загальну думку, але тоді говоріть абсолютно , ніби це завжди правда.
Роб Левін

3
@RobLevine: Я розумію ваш приклад і розумію, що ви пишете тести в таких випадках. Однак, як ви помітили, я справді йшов про більш загальну практику - так би мовити, тестування того, що повинен робити ваш код, порівняно з тестуванням того, чого ваш код не робить. Я трохи переформулював свою публікацію, щоб моя думка була чіткішою та ближчою до того, що я мав на увазі. Також надає можливість переглянути свій голос. Дякуємо за роз’яснення та вибачаємо за затримку відповіді.
км

4
голосування проти вилучено - наступного разу я не буду таким щасливим при голосуванні проти!
Роб Левін

4
У нашому проекті ми маємо клас htmlvalidator, який видає винятки, якщо html не є дійсним. Наприклад, при введенні користувачем (за допомогою консолі) javascript у розширеному комбо. Отже, у моєму коді випадку, що мій код робить, це не викидати виняток (підхід до білого списку), і мені потрібно перевірити це.
Machet

1
Не погодитися з цією відповіддю. Тестування на відсутність чогось іноді за певним сценарієм може бути валідним тестом.
bytedev

7

Цей допоміжний клас подряпав мій свербіж за допомогою MSTest. Можливо, це може подряпати і ваше.

[TestMethod]
public void ScheduleItsIneligibilityJob_HasValid_CronSchedule()
{
    // Arrange
    var factory = new StdSchedulerFactory();
    IScheduler scheduler = factory.GetScheduler();

    // Assert
    AssertEx.NoExceptionThrown<FormatException>(() =>
        // Act
        _service.ScheduleJob(scheduler)
    );
}

public sealed class AssertEx
{
    public static void NoExceptionThrown<T>(Action a) where T:Exception
    {
        try
        {
            a();
        }
        catch (T)
        {
            Assert.Fail("Expected no {0} to be thrown", typeof(T).Name);
        }
    }
}

@Remco Beurskens - додавання загального улову {} в кінці NoExceptionThrown <T> придушить інші помилки, що не є передбачуваним наслідком методу. Це не метод загального призначення для придушення всіх винятків. Він має на меті вийти з ладу лише тоді, коли виникає виняток відомого типу.
JJS

1
Зараз це дуже старе, але Assertмає односторонній доступ до властивостей, Thatякий можна використовувати як гачок для методів розширення. Це може бути акуратніше і більш що виявляється, щоб Assert.That.DoesNotThrow()замість AssertEx.DoesNotThrow(). Це лише думка.
Richard Hauer,

3

Мені подобається бачити Assert.Whatever в кінці кожного тесту, лише для узгодженості ... без нього, чи можу я справді бути впевненим, що там такого не повинно бути?

Для мене це так просто, як викласти Assert.IsTrue(true);

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

    [TestMethod]
    public void ProjectRejectsGappedVersioningByDefault() {

        var files = new List<ScriptFile>();
        files.Add(ScriptProjectTestMocks.GetVersion1to2());
        files.Add(ScriptProjectTestMocks.GetVersion3to4());

        Assert.Throws<ScriptProject.InvalidProjectFormatException>(() => {
            var sut = new ScriptProject(files);
        });

    }

    [TestMethod]
    public void ProjectAcceptsGappedVersionsExplicitly() {

        var files = new List<ScriptFile>();
        files.Add(ScriptProjectTestMocks.GetVersion1to2());
        files.Add(ScriptProjectTestMocks.GetVersion3to4());

        var sut = new ScriptProject(files, true);

        Assert.IsTrue(true);   // Assert.Pass() would be nicer... build it in if you like

    }

Це не те саме. Якщо ваш код викине, жодне твердження не буде вражено, і ваш тестовий запуск не вдасться. Ви хочете зачепити засіб тестування, затвердивши умову.
DvS

1

Мій друг Тім розповів мені про ExposedException . Мені дуже подобається цей б / к, він є більш стислим, менше коду, і дуже чітко, що ви тестуєте на виняток.

[TestMethod()]
[ExpectedException(typeof(System.Exception))]
public void DivideTest()
{
    int numerator = 4;
    int denominator = 0;
    int actual = numerator / denominator;
}

Детальніше про це ви можете прочитати тут: Використання атрибута ExpectedException .


1
ОП просить не виняток.
Даніель А. Уайт

Я залишаю цю відповідь тут. Я знайшов це питання під час пошуку в Google, як перевірити винятки, і ця відповідь, на мою думку, повинна бути тут. 7 років тому на їх запитання відповіли ОП. Навіть посилання на іншу відповідь, я вважаю корисним.
Джесс

Хороший Оле Тим. 🤔
jorffin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.