Значение модульных тестов высокого уровня и [закрытых] фиктивных объектов

Резюме: Нет.

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

Мы можем продемонстрировать это путем рассмотрения кода для этой функции, и с ++i и i++.

$ cat i++.c
extern void g(int i);
void f()
{
    int i;

    for (i = 0; i < 100; i++)
        g(i);

}

файлы являются тем же, за исключением ++i и i++:

$ diff i++.c ++i.c
6c6
<     for (i = 0; i < 100; i++)
---
>     for (i = 0; i < 100; ++i)

Мы скомпилируем их, и также получим сгенерированный ассемблер:

$ gcc -c i++.c ++i.c
$ gcc -S i++.c ++i.c

И мы видим, что и сгенерированные объектные и ассемблерные файлы являются тем же.

$ md5 i++.s ++i.s
MD5 (i++.s) = 90f620dda862cd0205cd5db1f2c8c06e
MD5 (++i.s) = 90f620dda862cd0205cd5db1f2c8c06e

$ md5 *.o
MD5 (++i.o) = dd3ef1408d3a9e4287facccec53f7d22
MD5 (i++.o) = dd3ef1408d3a9e4287facccec53f7d22
61
задан Landon Kuhn 7 July 2009 в 05:33
поделиться

5 ответов

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

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

Тесты более высокого уровня имеют свою ценность, но тогда они больше не называются модульными тестами; они называются интеграционными тестами и приемочными тестами. Интеграционные тесты необходимы, потому что они показывают, насколько хорошо различные программные компоненты работают вместе.

Приемочные испытания - это то, что заказчик подписывает. Приемочные тесты обычно пишут другие люди (не программист), чтобы представить другую точку зрения; программисты, как правило, пишут тесты того, что работает, тестировщики пытаются сломать это, проверяя то, что не работает.

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

Приемочные тесты обычно пишут другие люди (не программист), чтобы представить другую точку зрения; программисты, как правило, пишут тесты того, что работает, тестировщики пытаются сломать это, проверяя то, что не работает.

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

Приемочные тесты обычно пишут другие люди (не программист), чтобы представить другую точку зрения; программисты, как правило, пишут тесты того, что работает, тестировщики пытаются сломать это, проверяя то, что не работает.

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

44
ответ дан 24 November 2019 в 17:24
поделиться

Если вы выполняете TDD, вам следует писать тесты не после реализации, а наоборот. Таким образом, вы также избежите проблемы соответствия теста написанному коду. Вероятно, вам действительно нужно протестировать определенные вызовы методов в этих модулях, но не их последовательность (если это не обязательно для проблемы предметной области - бизнес-процесса).

И иногда вполне возможно не писать тест для определенного метода.

0
ответ дан 24 November 2019 в 17:24
поделиться

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

Похоже, что основной смысл имитационного тестирования состоит в том, чтобы менеджеры могли утверждать, что показатель покрытия кода равен Foo% .... так что все должно работать! Единственный исключительный случай, когда они могут оказаться полезными, - это когда вам нужно протестировать класс, который очень сложно воссоздать аутентично (например, тестирование класса действий в Struts).

Я большой сторонник написания сырых тестов. Реальный код с реальными объектами. Код внутри методов со временем будет меняться, но цель и, следовательно, общее поведение обычно не меняются.

3
ответ дан 24 November 2019 в 17:24
поделиться

В стороне

Просто коснусь вашего выделенного жирным шрифтом утверждения:

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

То, что является значением на верхнем уровне, является тестом интеграции. Есть веб-приложение? Вместо того, чтобы утверждать, что методы вашего контроллера возвращают ActionResult (малоценный тест), напишите интеграционный тест, который запрашивает все страницы в вашем приложении и проверяет, нет ли 404 или 403. Запускайте его один раз при каждом развертывании.

Окончательный ответ

Я всегда следую правилу 80/20 при модульном тестировании . Чтобы получить последние 20% покрытия на высоком уровне, о котором вы говорите, вам потребуется 80% ваших усилий. Для моих личных и большинства моих рабочих проектов, это не окупается.

Короче, я согласен. Я бы написал интеграционные тесты и проигнорировал бы модульные тесты для кода, который вы описываете.

20
ответ дан 24 November 2019 в 17:24
поделиться

In general, I consider testing this type of method/command to be ripe for the integration testing level. Specifically, I "unit test" for smaller, low level commands that (generally) don't have side effects. If I really want to unit test something that doesn't fit that model, the first thing I do is see if I can refactor/redesign to make it fit.

At the higher, integration (and/or system) testing level, I get into the testing of things that have side effects. I try to mock as little as possible (possibly only external resources) at this point. An example would be mocking the database layer to:

  1. Record how it was called to get data
  2. Return canned data Record how it was
  3. Record how it was called to insert manipulated data
0
ответ дан 24 November 2019 в 17:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: