Какова цель модульного тестирования? - PullRequest
2 голосов
/ 23 декабря 2011

В учебных целях я погрузился в область юнит-тестирования.Я прочитал несколько учебных пособий по этой проблеме с использованием QT и нашел следующее:

class QMyUnitTest : public QObject
{
    Q_OBJECT
private:
    bool isPrime(unsigned int ui);
private Q_SLOTS:
    void myTest();
};

bool QMyUnitTest::isPrime(unsigned int n) {
    typedef std::map<unsigned int, bool> Filter;
    Filter filter;

    for(unsigned int ui = 2; ui <= n; ui++) {
        filter[ui] = true;
    }
    unsigned int ui = filter.begin()->first;
    for(Filter::iterator it = filter.begin();
        it != filter.end(); it++) {
        if(it->second) {
            for(unsigned int uj = ui * ui; uj <= n; uj += ui) {
                filter[uj] = false;
            }
        }
        ui++;
    }
    return filter[n];
}

void QMyUnitTest::myTest() {
}

QTEST_MAIN(QMyUnitTest)
#include "tst_myunittest.moc"

Я знаю, что мой основной алгоритм поиска неэффективен и особенно некорректен;это подразумевается таким образом.Теперь я хочу провести тщательное тестирование, но возник следующий вопрос:

Для правильного тестирования мне не нужно иметь очень точное представление о том, что может пойти не так?

Конечно, я могу пробежать первые 1000 простых чисел и проверить, получаются ли они true или 1000, а не простые числа, и проверить, получаются ли они false, но это может не уловить недостатки алгоритма (например,: return filter[n]; явно ужасно, поскольку filter[n] может не существовать, если n<2).

Какой смысл использовать модульное тестирование, если я уже должен знать, каковы потенциальные проблемы моей функции?

Я что-то не так делаю?Есть ли лучший способ проверить?

Ответы [ 2 ]

14 голосов
/ 23 декабря 2011

Целью модульного тестирования является проверка того, что написанный вами код действительно выполняет то, что должен.

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

  • нормальные условия (т. Е. «Нормальные», «обычные» входы дают ожидаемый результат)
  • граничные условия (то есть ввод, который едва соответствует спецификации)
  • условия сбоя (т. Е. Вы проверяете, что ваш код некорректно работает, когда ввод неверен).

Ваш хороший пример проверки поведения вашей подпрограммы isPrime с числами, которые она не обрабатывает. Не зная вашей реализации, 0, 1, 2 и отрицательные значения были бы хорошими тестовыми сценариями для подпрограммы isPrime - это вещи, о которых вы не могли бы подумать при реализации своего алгоритма, поэтому они являются ценными тестами.

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

Какой смысл использовать модульное тестирование, если я уже должен знать, каковы потенциальные проблемы моей функции?

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

9 голосов
/ 23 декабря 2011

Просто хочу добавить к тому, что Mat уже перечислил:

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

  • Если написано правильно, модульные тесты станут отличным способом документировать поведение вашего кода.

...