Сведения о вопросе

FELL

03:25, 1st August, 2020

Теги

Тестовые утверждение против утверждения

Просмотров: 460   Ответов: 5

В моем самом C++ проекте я активно использовал оператор ASSERTION следующим образом:

int doWonderfulThings(const int* fantasticData)
{
    ASSERT(fantasticData);
    if(!fantasticData)
        return -1;
    // ,,,
    return WOW_VALUE;
}

Но сообщество TDD, похоже, любит делать что-то подобное:

int doMoreWonderfulThings(const int* fantasticData)
{
    if(!fantasticData)
        return ERROR_VALUE;
    // ...
    return AHA_VALUE;
}

TEST(TDD_Enjoy)
{
    ASSERT_EQ(ERROR_VALUE, doMoreWonderfulThings(0L));
    ASSERT_EQ(AHA_VALUE, doMoreWonderfulThings("Foo"));
}

Просто с моим опытом первые подходы позволили мне удалить так много тонких ошибок. Но подходы TDD-это очень умная идея для обработки устаревших кодов.

"Google"-они сравнивают "FIRST METHOD" с "ходить по берегу со спасательным жилетом, плавать по океану без всякого безопасного охранника".

Какой из них лучше? Какой из них делает программное обеспечение надежным?



  Сведения об ответе

SKY

06:24, 2nd August, 2020

По моему (ограниченному) опыту, первый вариант довольно безопасен. В тестовом случае вы проверяете только предопределенные входные данные и сравниваете результат, это хорошо работает до тех пор, пока каждый возможный крайний случай был проверен. Первый вариант просто проверяет все входные данные и таким образом проверяет значения 'live', он очень быстро отфильтровывает ошибки, однако он поставляется со штрафом за производительность.

В Code Complete Steve McConnell учит нас, что первый метод может быть успешно использован для фильтрации ошибок в отладочной сборке. В сборке выпуска вы можете отфильтровать все утверждения (например, с флагом компилятора), чтобы получить дополнительную производительность.

На мой взгляд лучше всего использовать оба метода:

Метод 1 для перехвата незаконных значений

int doWonderfulThings(const int* fantasticData)
{
    ASSERT(fantasticData);
    ASSERTNOTEQUAL(0, fantasticData)

    return WOW_VALUE / fantasticData;
}

и Метод 2 для проверки крайних случаев алгоритма.

int doMoreWonderfulThings(const int fantasticNumber)
{
    int count = 100;
    for(int i = 0; i < fantasticNumber; ++i) {
        count += 10 * fantasticNumber;
    }
    return count;
}

TEST(TDD_Enjoy)
{
    // Test lower edge
    ASSERT_EQ(0, doMoreWonderfulThings(-1));
    ASSERT_EQ(0, doMoreWonderfulThings(0));
    ASSERT_EQ(110, doMoreWonderfulThings(1));

    //Test some random values
    ASSERT_EQ(350, doMoreWonderfulThings(5));
    ASSERT_EQ(2350, doMoreWonderfulThings(15));
    ASSERT_EQ(225100, doMoreWonderfulThings(150));
}


  Сведения об ответе

nYU

23:36, 28th August, 2020

Оба механизма имеют ценность. Любой приличный тестовый фреймворк все равно поймает стандартный assert(), поэтому тестовый запуск, который вызывает сбой assert, приведет к неудачному тесту.

Обычно у меня есть ряд утверждений в начале каждого метода c++ с комментарием "/ / предварительные условия"; это просто проверка на вменяемость состояния, которое я ожидаю от объекта при вызове метода. Они прекрасно вписываются в любой фреймворк TDD, потому что они не только работают во время выполнения, когда вы тестируете функциональность, но и работают во время тестирования.


  Сведения об ответе

Chhiki

21:06, 1st October, 2020

Нет никакой причины, по которой ваш тестовый пакет не может поймать утверждения, такие как в doMoreWonderfulThings. Это можно сделать либо с помощью вашего обработчика ASSERT, поддерживающего механизм обратного вызова, либо с помощью тестовых утверждений, содержащих блок try/catch.


  Сведения об ответе

fo_I_K

18:18, 11th August, 2020

Я не знаю, к какому субобществу particlar TDD вы относитесь, но паттерны TDD, с которыми я столкнулся, либо используют Assert.AreEqual() для положительных результатов, либо иным образом используют механизм ExpectedException (например, атрибуты in .NET) объявить ошибку, которую следует соблюдать.


  Сведения об ответе

appple

03:21, 11th August, 2020

В C++ я предпочитаю Метод 2 при использовании большинства платформ тестирования. Обычно это облегчает понимание отчетов о неудачах. Это бесценно, когда тест проходит от нескольких месяцев до нескольких лет после написания теста.

Моя причина заключается в том, что большинство платформ тестирования C++ будут печатать файл и номер строки, где произошло утверждение, без какой-либо информации о стеке trace. Поэтому большую часть времени вы будете получать номер строки отчета внутри функции или метода, а не внутри тестового набора.

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

Но есть и исключения. Например, у тестовой платформы Google есть оператор scoped trace, который будет печататься как часть trace, если возникнет исключение. Таким образом, вы можете обернуть вызов обобщенной тестовой функции с областью видимости trace и легко сказать, в пределах одной или двух строк, какая строка в точном тестовом случае не удалась.


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться