Это Утверждение.Не() считается плохой практикой?


Я использую Assert.Терпеть неудачу много при выполнении TDD. Обычно я работаю над одним тестом за раз, но когда я получаю идеи для вещей, которые я хочу реализовать позже, я быстро пишу пустой тест, где имя метода теста указывает, что я хочу реализовать как своего рода список задач. Чтобы убедиться, что я не забыл, я поставил утверждение.Fail () в теле.

при попытке xUnit.Net я обнаружил, что они не реализовали Assert.Неудача. Конечно, вы всегда можете утверждать.IsTrue (false) но это не так сообщи и о моем намерении. У меня сложилось такое впечатление.Сбой не был реализован специально. Это считается плохой практикой? Если да, то почему?


@Martin Meredith Это не совсем то, что я делаю. Сначала я пишу тест, а затем реализую код, чтобы заставить его работать. Обычно я думаю о нескольких тестах сразу. Или я думаю о тесте, чтобы написать, когда я работаю над чем-то еще. Вот когда я пишу пустой провальный тест, чтобы помнить. К тому времени, как я приступаю к написанию теста, я аккуратно работаю тест-первый.

@Jimmeh Похоже, это хорошая идея. Проигнорированные тесты не терпят неудачу, но они все еще появляются в отдельном списке. Надо попробовать.

@Matt Howells великая идея. NotImplementedException передает намерение лучше, чем assert.Fail () в этом случае

@Mitch Пшеница Это то, что я искал. Кажется, он был оставлен, чтобы предотвратить его злоупотребление другим способом, которым я его злоупотребляю.

13 65

13 ответов:

для этого сценария, а не вызова assert.Сбой, я делаю следующее (В C# / NUnit)

[Test]
public void MyClassDoesSomething()
{
    throw new NotImplementedException();
}

это более явно, чем утверждение.Неудача.

[Test]
public void ThrowsExceptionCorrectly()
{
    const string BAD_INPUT = "bad input";
    try
    {
        new MyClass().DoSomething(BAD_INPUT);
        Assert.Fail("No exception was thrown");
    }
    catch (MyCustomException ex)
    {
         Assert.AreEqual(BAD_INPUT, ex.InputString); 
    }
}

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

Это было намеренно. Это ответ Брэда Уилсона на вопрос, почему нет утверждения.Fail ():

мы не пропустили это, на самом деле. Я найдите утверждение.Неудача-это костыль, который подразумевает, что, вероятно, есть утверждение отсутствует. Иногда это просто способ структурирования теста, а также иногда это потому, что утверждать может используйте другое утверждение.

Я всегда использовал Assert.Fail () для обработки случаев, когда вы обнаружили, что тест должен завершиться неудачей с помощью логики, выходящей за рамки простого сравнения значений. В качестве примера:

try 
{
  // Some code that should throw ExceptionX
  Assert.Fail("ExceptionX should be thrown")
} 
catch ( ExceptionX ex ) 
{
  // test passed
}

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

Что касается вашей практики создания тестов, которые намеренно не удается в вашем рабочем пространстве, чтобы напомнить себе, чтобы реализовать их перед совершением, это кажется мне прекрасной практикой.

Я использую MbUnit для моего модульного тестирования. У них есть возможность игнорировать тесты, которые отображаются как оранжевый (а не зеленый или красный) в наборе тестов. Возможно, xUnit имеет что-то подобное, и это означает, что вам даже не нужно вводить какое-либо утверждение в метод, потому что оно будет отображаться в раздражающе другом цвете, что затруднит его пропустить?

Edit:

в MbUnit это происходит следующим образом:

[Test]
[Ignore]
public void YourTest()
{ } 

это шаблон, который я использую при написании теста для кода, который я хочу бросить исключение по дизайну:

[TestMethod]
public void TestForException()
{
    Exception _Exception = null;

    try
    {
        //Code that I expect to throw the exception.
        MyClass _MyClass = null;
        _MyClass.SomeMethod();
        //Code that I expect to throw the exception.
    }
    catch(Exception _ThrownException)
    {   
        _Exception = _ThrownException
    }
    finally
    {
        Assert.IsNotNull(_Exception);
        //Replace NullReferenceException with expected exception.
        Assert.IsInstanceOfType(_Exception, typeof(NullReferenceException));
    }
}

IMHO это лучший способ тестирования исключений с помощью Assert.Неудача.)( Причина этого заключается в том, что я не только тестирую исключение, но и тестирую тип исключения. Я понимаю, что это похоже на ответ от Мэтта Хауэлла, но IMHO, использующий блок finally, более надежен.

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

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

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

кстати в MSTest, стандартный шаблон теста использует Assert.Неубедительно в конце своих образцов.

AFAIK the xUnit.NET фреймворк призван быть чрезвычайно легким, и да, они намеренно сократили неудачу, чтобы побудить разработчика использовать явное условие отказа.

Wild guess: удержание утверждения.Fail предназначен для того, чтобы вы перестали думать, что хороший способ написать тестовый код-это огромная куча спагетти, ведущая к утверждению.Не в плохих случаях. [Edit to add: ответы других людей в целом подтверждают это, но с цитатами]

Так как это не то, что вы делаете, вполне возможно, что xUnit.Net это чрезмерная защита.

I предпочитаю реализовывать функцию под названием ThisCodeHasNotBeenWrittenYet (на самом деле что-то короче, для удобства ввода). Невозможно передать намерение более четко, чем это, и у вас есть точный поисковый запрос.

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

С хорошим кодом я обычно делаю:

void goodCode() {
     // TODO void goodCode()
     throw new NotSupportedOperationException("void goodCode()");
}

С тестовым кодом я обычно делаю:

@Test
void testSomething() {
     // TODO void test Something
     Assert.assert("Some descriptive text about what to test")
}

Если вы используете JUnit и не хотите получить сбой, но ошибку, то я обычно делаю:

@Test
void testSomething() {
     // TODO void test Something
     throw new NotSupportedOperationException("Some descriptive text about what to test")
}

Почему бы вам использовать Assert.Не удалось сказать, что исключение должно быть брошено? В этом нет необходимости. Почему бы просто не использовать атрибут ExpectedException?

будьте осторожны Assert.Fail и его тлетворное влияние, чтобы заставить разработчиков писать глупые или сломанные тесты. Например:

[TestMethod]
public void TestWork()
{
    try {
        Work();
    }
    catch {
        Assert.Fail();
    }
}

это глупо, потому что try-catch является избыточным. Тест завершается неудачно, если он создает исключение.

и

[TestMethod]
public void TestDivide()
{
    try {
        Divide(5,0);
        Assert.Fail();
    } catch { }
}

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

Если вы пишете тест, который просто терпит неудачу, а затем пишете код для него, а затем пишете тест. Это не тестовая разработка.

Технически, Утверждают.fail () не должен быть необходим, если вы используете тестовую разработку правильно.

вы думали об использовании списка задач или применении методологии GTD к своей работе?

MS тест имеет Assert.Fail (), но он также имеет Assert.Неубедительно (). Я думаю, что наиболее подходящее использование для Assert.Fail ()-это если у вас есть какая-то встроенная логика, которую было бы неудобно вводить в утверждение, хотя я даже не могу придумать хороших примеров. По большей части, если тестовая платформа поддерживает что-то другое, чем Assert.Fail () затем используйте это.

Я думаю, вы должны спросить себя, что (авансовое) тестирование должно делать.

во-первых, вы пишете (набор) тест без реализации. Может быть, и сценарии на черный день.

все эти тесты должны потерпеть неудачу, чтобы быть правильным тестов: Таким образом, вы хотите достичь двух вещей: 1) Убедитесь, что ваша реализация-это правильно; 2) Убедитесь, что ваш юнит-тесты являются правильными.

теперь, если вы делаете upfront TDD, вы хотите выполнить все свои тесты, а также части NYI. Результат ваш общий тестовый прогон проходит, если: 1) все реализованные вещи успешно 2) все NYI вещи терпит неудачу

В конце концов, это будет модульный тест ommision, если ваши модульные тесты будут успешными, пока нет реализации, не так ли?

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

просто напишите [игнорировать] тесты не будет делать эту работу. Ни один из них не утверждает, что останавливает первый сбой утверждения, а не запускает другие строки тестов в тесте.

теперь, как достичь этого? Я думаю, что это требует более продвинутой организации вашего тестирования. И для достижения этих целей требуется какой-то другой механизм, который затем утверждает.

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

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

тем не менее, сборка CI, которая отправляет по почте, если не все тесты в отделе NYI терпят неудачу, нелегка и прямолинейна.