Re[10]: дебагинг vs unit-тесты vs ассерты
От: Кодт Россия  
Дата: 04.05.16 11:59
Оценка: :)
Здравствуйте, landerhigh, Вы писали:

L>Я, кажется, знаю, куда эта дискуссия ведет — поскольку юнит-тесты не отлавливают расстрел памяти в сферическом случае в в вакууме, то и писать их не будем. Я такое видел 100500 раз.


Нет, пока что я вижу, куда ты тянешь дискуссию: "поскольку юнит-тесты — это круто, давайте выкинем отладчик".
Проект хромиума покрыт тестами сверху донизу, но их настолько недостаточно, что приходится иногда даже трахаться с gdb в командной строке.



К>>Ну давай, покажи простой и эффективный код транспонирования матрицы на месте.

L>Э, нет, я тут про тесты говорю, а не матирцы.

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

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

К>>Если будешь рожать "с листа", то риск накосячить с адресной арифметикой достаточно велик.

L>Ключевое слово "риск". Привыкший работать по TDD моментально распознает эти риски. И задает себе вопрос — как я напишу тест, который проверит, накосячил ли я в данном месте? Это не всегда можно, но чаще всего — как раз можно.

До какой степени детализации ты будешь обкладывать код тестами?
void go_around_zero(int n) { for(int i = -n*10; i <= n*10; ++i) { do_smth(); } }
// TODO отрефакторить, чтобы покрыть тестами

ну поехали, что ли!
int ten_times(int x) { return x*10; }
// TODO покрыть тестами умножение на 10

void go_around_zero(int n) { for(int i = ten_times(-n), e = ten_times(n); i <= e; ++i) { do_smth(); } }
// TODO тесты для go_around_zero

начнём...
// названия макросов тестов вымышлены, по мотивам GTest.
TEST(TenTimes, ZeroIsZero)         { EXPECT_EQ(  0, ten_times( 0); }
TEST(TenTimes, PositiveIsPositive) { EXPECT_EQ(+10, ten_times(+1); }
TEST(TenTimes, NegativeIsNegative) { EXPECT_EQ(-10, ten_times(-1); }

потом, ах да, переполнение!
int ten_times(int x) {
  assert(abs(x) <= std::limits<int>::max() / 10; }
  return x*10;
}
TEST(TenTimes, PositiveOk)       { ASSERT_PASS(ten_times(+INT_MAX/10)); }
TEST(TenTimes, NegativeOk)       { ASSERT_PASS(ten_times(-INT_MAX/10)); }
TEST(TenTimes, PositiveOverflow) { ASSERT_FAIL(ten_times(+INT_MAX/10 + 1)); }
TEST(TenTimes, NegativeOverflow) { ASSERT_FAIL(ten_times(-INT_MAX/10 - 1)); }

(кстати, два UB, связанные с переполнением, я специально оставил на сладкое; причём одно добавилось в ходе написания теста...)

А в это время в Виллабаджо уже делают фигак-фигак-продакшен.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.