Assert.Fail () считается плохой практикой? - PullRequest
66 голосов
/ 23 сентября 2008

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

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


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

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

@ Мэтт Хауэллс Отличная идея. NotImplementedException сообщает о намерении лучше, чем assert.Fail () в этом случае

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

Ответы [ 13 ]

51 голосов
/ 23 сентября 2008

Для этого сценария вместо вызова Assert.Fail я делаю следующее (в C # / NUnit)

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

Это более явно, чем Assert.Fail.

Кажется, существует общее согласие, что предпочтительнее использовать более явные утверждения, чем Assert.Fail (). Большинство фреймворков должны включать его, потому что они не предлагают лучшей альтернативы. Например, NUnit (и другие) предоставляют атрибут ExpectedExceptionAttribute для проверки того, что некоторый код генерирует определенный класс исключений. Однако, чтобы проверить, что свойству исключения присвоено определенное значение, его нельзя использовать. Вместо этого вы должны прибегнуть к Assert.Fail:

[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.Throws делает это намного лучше, не требуя метода Assert.Fail. Не включая метод Assert.Fail (), xUnit.Net поощряет разработчиков находить и использовать более явные альтернативы, а также поддерживать создание новых утверждений, где это необходимо.

17 голосов
/ 23 сентября 2008

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

Мы не упустили это из виду. я найти Assert.Fail это костыль, который подразумевает, что утверждение отсутствует. Иногда это просто как устроен тест, и иногда это потому, что Assert мог используйте другое утверждение.

9 голосов
/ 23 сентября 2008

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

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

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

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

5 голосов
/ 23 сентября 2008

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

Редактировать:

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

[Test]
[Ignore]
public void YourTest()
{ } 
4 голосов
/ 26 июня 2009

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

[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));
    }
}

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

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

3 голосов
/ 23 сентября 2008

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

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

Между прочим, в MSTest стандартный шаблон Test использует Assert.Inconclusive в конце своих образцов.

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

2 голосов
/ 28 августа 2014

Остерегайтесь Assert.Fail и его разрушающего влияния, чтобы заставить разработчиков писать глупые или неработающие тесты. Например:

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

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

Также

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

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

2 голосов
/ 23 сентября 2008

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

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")
}
2 голосов
/ 23 сентября 2008

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

Поскольку это не то, что вы делаете, возможно, xUnit.Net чрезмерно защищает.

Или, может быть, они просто думают, что это так редко и так неортогонально, что не нужно.

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

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

1 голос
/ 25 октября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...