Как проверить, что «исключений не было» в модульном тесте MSTest?


88

Я пишу модульный тест для этого единственного метода, который возвращает «void». Я хотел бы иметь один случай, когда тест проходит, когда нет исключения. Как мне написать это на C #?

Assert.IsTrue(????)

(Я предполагаю, что именно так я должен проверить, но что входит в "???")

Надеюсь, мой вопрос достаточно ясен.


Вы используете MSTest или NUnit?
Мэтт Гранде,

2
В MSTest неперехваченные исключения автоматически приводят к сбою тестов. Вы пытаетесь учесть обнаруженные исключения?
Фил

Вы можете найти "try-catch for C #", и он проинструктирует вас, как обрабатывать генерируемые или не генерируемые исключения.
Foggzie

1
Если NUnit, посмотрите Assert.That (lambda) .Throws.Nothing (хотя я думаю, что это недавно изменилось)
Мэтт Гранде

Ответы:


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)


Очевидно, вы не должны ловить такие исключения, чтобы это было правдой.
Servy

7
Тест завершится неудачно, только если будет выброшено неперехваченное исключение. В зависимости от кода в обработчиках исключений модульные тесты могут пройти.
ediblecode

1
Это полезно для Ms Unittest, поэтому в Unittest нет метода Assert.DoesNotThrow (().
Башар Кая

25

В NUnit вы можете использовать:

Assert.DoesNotThrow(<expression>); 

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

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


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.
Дэн Чарпстер,

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

11

Не проверяйте, что чего-то не происходит . Это похоже на гарантию того, что код не сломается . Это как бы подразумевает, что все мы стремимся к неразрывному и безошибочному коду. Вы хотите написать для этого тесты? Почему только один метод? Разве вы не хотите, чтобы все ваши методы проверялись и не вызывали исключения ? Следуя по этому пути, вы получите один дополнительный фиктивный тест без утверждений для каждого метода в вашей базе кода. Это не приносит никакой ценности.

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

Однако общий подход / практика остаются неизменными - вы не пишете тесты для некоторых искусственных / расплывчатых требований, которые выходят за рамки тестируемого кода (и проверка того, что «работает» или «не работает», обычно является примером такие - особенно в сценарии, когда обязанности метода хорошо известны).

Проще говоря - сосредоточьтесь на том, что должен делать ваш код , и проверьте это.


10
-1 Я могу думать о положительной функциональности, которая требует, чтобы исключение не создавалось. Во-первых, метод, задача которого - обрабатывать исключения, регистрировать их и принимать меры - без дальнейшей генерации исключения. Вы делаете хорошее общее замечание, но затем говорите абсолютно, как будто это всегда правда.
Роб Левин

3
@RobLevine: Я понимаю ваш пример и понимаю, что вы пишете тесты в таких случаях. Тем не менее, как вы заметили, я действительно имел в виду более общую практику - так сказать, тестирование того, что должен делать ваш код, по сравнению с тестированием того, чего ваш код не делает. Я немного перефразировал свой пост, чтобы моя точка зрения была более ясной и ближе к тому, что я имел в виду. Также дает вам возможность пересмотреть свой голос. Благодарим за разъяснения и извиняемся за задержку с ответом.
km

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(). Это всего лишь мнение.
Ричард Хауэр

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

Мой друг Тим рассказал мне об ExpectedException . Мне очень нравится этот b / c, он более лаконичный, меньше кода и очень ясно, что вы тестируете исключение.

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

Подробнее об этом можно прочитать здесь: Использование атрибута ExpectedException .


1
ОП не просит исключений.
Дэниел А. Уайт

Я оставлю этот ответ здесь. Я нашел этот вопрос, когда искал в Google, как тестировать исключения, и этот ответ, я думаю, должен быть здесь. OP получил ответ на свой вопрос 7 лет назад. Я думаю, что даже ссылка на другой ответ полезна.
Джесс

Добрый оле Тим. 🤔
ruffin
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.