«Код покрыт» против «Код проверен»? - PullRequest
2 голосов
/ 04 октября 2008

Преобразуя мой текущий проект кода в TDD, я кое-что заметил.

class Foo {
    public event EventHandler Test;

    public void SomeFunction() {
        //snip...
        Test(this, new EventArgs());
    }
}

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

  • Вы должны проверять, происходит ли событие Test. Только инструменты покрытия кода не сообщат вам, если вы забудете это.
  • Я доберусь до другого через секунду.

Для этого я добавил обработчик событий в свою функцию запуска, чтобы он выглядел так:

Foo test;
int eventCount;

[Startup] public void Init() {
    test = new Foo();
    // snip...
    eventCount = 0;
    test.Test += MyHandler;
}

void MyHandler(object sender, EventArgs e) { eventCount++; }

Теперь я могу просто проверить eventCount, чтобы увидеть, сколько раз было вызвано мое событие, если оно было вызвано. Довольно аккуратно. Только теперь мы пропустили коварную небольшую ошибку, которая никогда не будет обнаружена никаким тестом, а именно: SomeFunction() не проверяет, есть ли у события обработчики, прежде чем пытаться вызвать его. Это вызовет нулевую разыменовку, которая никогда не будет обнаружена ни одним из наших тестов, потому что к ним все по умолчанию подключен обработчик событий. Но опять же, инструмент покрытия кода все равно сообщит о полном покрытии.

Это всего лишь мой «пример из реальной жизни», но мне приходит в голову, что гораздо больше таких ошибок может проскользнуть, даже при 100% «покрытии» вашего кода, это все равно не переводится 100% проверено. Должны ли мы взять покрытие, о котором сообщает такой инструмент, с долей соли при написании тестов? Существуют ли другие виды инструментов, которые бы ловили эти дыры?

Ответы [ 7 ]

4 голосов
/ 04 октября 2008

<100% кодовое покрытие плохо, но это не значит, что 100% кодовое покрытие хорошо. Это необходимое, но недостаточное условие, и к нему следует относиться. </p>

Также обратите внимание, что существует разница между покрытием кода и покрытием пути:

void bar(Foo f) {
    if (f.isGreen()) accountForGreenness();
    if (f.isBig()) accountForBigness();
    finishBar(f);
}

Если вы передадите большой, зеленый Foo в этот код в качестве тестового примера, вы получите 100% покрытие кода. Но, как вы знаете, большой красный Foo может привести к сбою системы, потому что accountForBigness неверно предполагает, что какой-то указатель не равен NULL, что только делает NULL ненулевым с помощью accountForGreenness. У вас не было 100% покрытия пути, потому что вы не покрыли путь, который пропускает вызов accountForGreenness, но не призыв к accountForBigness.

Также возможно получить 100% покрытие филиала без 100% покрытия пути. В приведенном выше коде один вызов с большим зеленым Foo, а другой с маленьким красным Foo дает первый, но все еще не улавливает большой красный баг.

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

4 голосов
/ 04 октября 2008

Я бы не сказал «бери с крошкой соли» (есть много полезности для кодирования покрытия), но процитирую себя

TDD и покрытие кода не являются панацея:

· Даже с блоком 100% покрытие, все еще будут ошибки в условиях, которые выбирают какие блоки для выполнения.

· Даже с блоком 100% покрытие + 100% покрытие дуги, есть все еще будут ошибки в прямой линии Код.

· Даже с блоком 100% покрытие + 100% покрытие дуги + 100% безошибочный-для-на-наименее-один путь прямой код, там еще будет быть входными данными, которые выполняются пути / петли способами, которые показывают больше ошибки.

(из здесь )

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

2 голосов
/ 04 октября 2008

Должны ли мы брать покрытие, о котором сообщает такой инструмент, с долей соли при написании тестов?

Абсолютно. Инструмент покрытия только сообщает вам, какая часть строк в вашем коде была на самом деле запущена во время тестов. Это ничего не говорит о том, насколько тщательно эти линии были проверены . Некоторые строки кода должны быть проверены только один или два раза, но некоторые должны быть проверены на широком диапазоне входных данных. Инструменты покрытия не могут определить разницу.

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

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

0 голосов
/ 04 октября 2008

Тестирование абсолютно необходимо. То, что также должно быть согласовано, является реализацией.

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

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

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

0 голосов
/ 04 октября 2008

Да, это основное отличие между «покрытием линии» и «покрытием пути». На практике вы не можете измерить охват пути кода. Подобно статическим проверкам времени компиляции, модульным тестам и статическому анализу - покрытие строк - это еще один инструмент, который можно использовать в поисках качественного кода.

0 голосов
/ 04 октября 2008

Покрытие действительно полезно только для идентификации кода, который еще не был протестирован. Это не говорит вам много о коде, который был покрыт.

...