Каковы за и против автоматизированных Модульных тестов по сравнению с автоматизированными Интеграционными тестами?

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

Вы должны иметь:

function drawChart(placeholder, values1, labels1) {
    var plot = $.plot(placeholder,
        [{
            data: values1,
            label: label1,
            lines: {
                show: true,
                lineWidth: 2,
                fill: true,

            },
            points: {
                show: true,
                lineWidth: 3,
                fill: true,
                fillColor: '#fafafa'
            }

        }]
    });
}
28
задан WW. 21 April 2009 в 04:15
поделиться

12 ответов

Вы спрашиваете о плюсах и минусах двух разных вещей (каковы плюсы и минусы езды на лошади против мотоцикла?)

Конечно, оба являются «автоматизированными тестами» (~ верхом), но это не означает, что они являются альтернативой (вы не ездите на лошади на протяжении сотен миль, и вы не ездите на мотоцикле в грязных местах с закрытыми транспортными средствами)


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

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

Нет смысла проводить ручные юнит-тесты.

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

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


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

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


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

В вашем случае, я бы предпочел использовать подход «среднего уровня»:

  1. меньшие интеграционные тесты, которые проверяют только те секции, которые вы собираетесь реорганизовать. Если вы проводите рефакторинг всего этого, то вы можете использовать свои текущие интеграционные тесты, но если вы рефакторинг только - скажем - генерация XML, нет смысла требовать наличия базы данных, поэтому я бы написал простой и небольшой тест интеграции XML.
  2. куча модульных тестов для нового кода, который вы собираетесь написать. Как я уже писал выше, модульные тесты будут готовы, как только вы «возитесь с чем-то промежуточным», убедившись, что ваш «беспорядок» куда-то уходит.

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

  • , почему он не работает
  • если ваша отладка "беспорядка" действительно что-то исправляет
  • если ваша отладка "беспорядка" ломает что-то еще

Интеграционные тесты дадут подтверждение в конце, только если все изменение было успешным (и ответ будет «нет» в течение длительного времени). Интеграционные тесты не окажут вам никакой помощи во время самого рефакторинга, что сделает его более трудным и, возможно, разочаровывающим. Для этого вам нужны юнит-тесты.

28
ответ дан 28 November 2019 в 02:16
поделиться

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


(подробнее ...)

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

long pow2(int p); // returns 2^p for 0 <= p <= 30

Ваш тест и ваша спецификация выглядят практически одинаково (это своего рода псевдо-xUnit для иллюстрации):

assertEqual(1073741824,pow2(30);
assertEqual(1, pow2(0));
assertException(domainError, pow2(-1));
assertException(domainError, pow2(31));

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

Если вы измените реализацию так, что, скажем, она возвращает 16 бит (помните, что sizeof (long) гарантированно будет иметь размер не менее sizeof (short) ), тогда эти тесты быстро пройдут неудачно. Тест на уровне интеграции, вероятно, должен провалиться, но не обязательно, и это так же вероятно, как и то, что он не потерпит неудачу где-то далеко вниз по течению от вычисления pow2 (28) .

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

34
ответ дан 28 November 2019 в 02:16
поделиться

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

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

2) Второе значение единицы Тесты в том, что если они правильно написаны, они очень, очень быстро. Если я внесу изменения в класс в вашем проекте, могу ли я запустить все соответствующие тесты, чтобы проверить, не нарушил ли я что-нибудь? Как узнать, какие тесты нужно запустить? И сколько они займут? Я могу гарантировать, что это будет дольше, чем хорошо написанные модульные тесты. Вы должны быть в состоянии выполнить все свои юнит-тесты максимум за пару минут.

20
ответ дан 28 November 2019 в 02:16
поделиться

Just a few examples from personal experience:

Unit Tests:

  • (+) Keeps testing close to the relevant code
  • (+) Relatively easy to test all code paths
  • (+) Easy to see if someone inadvertently changes the behavior of a method
  • (-) Much harder to write for UI components than for non-GUI

Integration Tests:

  • (+) It's nice to have nuts and bolts in a project, but integration testing makes sure they fit each other
  • (-) Harder to localize source of errors
  • (-) Harder to tests all (or even all critical) code paths

Ideally both are necessary.

Examples:

  • Unit test: Make sure that input index >= 0 and < length of array. What happens when outside bounds? Should method throw exception or return null?

  • Integration test: What does the user see when a negative inventory value is input?

The second affects both the UI and the back end. Both sides could work perfectly, and you could still get the wrong answer, because the error condition between the two isn't well-defined.

The best part about Unit testing we've found is that it makes devs go from code->test->think to think->test->code. If a dev has to write the test first, [s]he tends to think more about what could go wrong up front.

To answer your last question, since unit tests live so close to the code and force the dev to think more up front, in practice we've found that we don't tend to refactor the code as much, so less code gets moved around - so tossing and writing new tests constantly doesn't appear to be an issue.

16
ответ дан 28 November 2019 в 02:16
поделиться

Unit tests execute methods in a class to verify proper input/output without testing the class in the larger context of your application. You might use mocks to simulate dependent classes -- you're doing black box testing of the class as a stand alone entity. Unit tests should be runnable from a developer workstation without any external service or software requirements.

Integration tests will include other components of your application and third party software (your Oracle dev database, for example, or Selenium tests for a webapp). These tests might still be very fast and run as part of a continuous build, but because they inject additional dependencies they also risk injecting new bugs that cause problems for your code but are not caused by your code. Preferably, integration tests are also where you inject real/recorded data and assert that the application stack as a whole is behaving as expected given those inputs.

The question comes down to what kind of bugs you're looking to find and how quickly you hope to find them. Unit tests help to reduce the number of "simple" mistakes while integration tests help you ferret out architectural and integration issues, hopefully simulating the effects of Murphy's Law on your application as a whole.

2
ответ дан 28 November 2019 в 02:16
поделиться

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

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

Интеграционные тесты тестируют поведение И инфраструктуру. Юнит-тесты обычно только тестируют поведение.

Итак, юнит-тесты хороши для тестирования некоторых вещей, интеграционных тестов для других вещей.

Итак, почему юнит-тест?

Например, очень сложно протестировать граничные условия когда интеграционное тестирование. Пример: внутренняя функция ожидает положительное целое число или 0, внешний интерфейс не позволяет вводить отрицательное целое число, как вы гарантируете, что внутренняя функция ведет себя правильно, когда вы передаете ей отрицательное целое число? Может быть, правильное поведение - бросить исключение. Это очень сложно сделать с помощью интеграционного теста.

Итак, для этого вам нужен модульный тест (функции).

Кроме того, модульные тесты помогают устранить проблемы, обнаруженные во время интеграционных тестов. проверка сервлета вызов из сервлета на бизнес-уровень проверка бизнес-уровня чтение базы данных (спящий режим) преобразование данных бизнес-уровнем запись в базу данных (спящий режим) преобразование данных -> XML преобразование XSLT -> HTML передача HTML -> client

Чтобы ваши интеграционные тесты работали, вам нужно, чтобы ВСЕ эти процессы работали правильно. Для модульного тестирования валидации сервлета вам нужен только один. Проверка сервлета (которая может быть независимой от всего остального). Проблему в одном слое легче отследить.

Вам нужны и модульные тесты, и интеграционные тесты.

3
ответ дан 28 November 2019 в 02:16
поделиться

Джоэл Спольски написал очень интересную статью о юнит-тестировании (это был диалог между Джоэлом и каким-то другим парнем).

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

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

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

Как я использую модульные тесты: я не Мне нравится TDD, поэтому я сначала пишу код, а затем тестирую его (используя консоль или браузер), просто чтобы убедиться, что этот код выполняет ненужную работу. И только после этого я добавляю «хитрые» тесты - 50% из них проваливаются после первого тестирования.

Это работает и не занимает много времени.

2
ответ дан 28 November 2019 в 02:16
поделиться

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

Я не вижу, как добавить еще кучу модульные тесты на отдельных классах будут Помогите. Разве это не затруднит рефакторинг, как это гораздо более вероятно, мы нужно будет выбросить и переписать тесты?

Нет. Это сделает рефакторинг легче и лучше, и сделает более ясным, чтобы увидеть, какие рефакторинг уместен и уместен. Вот почему мы говорим, что TDD - это дизайн, а не тестирование. Я довольно часто пишу тест для одного метода и выясняю, как выразить, каким должен быть результат этого метода, чтобы придумать очень простую реализацию с точки зрения какого-либо другого метода тестируемого класса. Эта реализация часто попадает в тестируемый класс. Более простые, более надежные реализации, более четкие границы, меньшие методы: TDD - модульные тесты, в частности - ведут вас в этом направлении, а интеграционные тесты - нет. Они оба важны, оба полезны, но служат разным целям.

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

2
ответ дан 28 November 2019 в 02:16
поделиться

Хотя описанная вами установка звучит хорошо, модульное тестирование также предлагает кое-что важное. Модульное тестирование предлагает высокий уровень детализации. С помощью слабой связи и внедрения зависимостей вы можете в значительной степени протестировать каждый важный случай. Вы можете быть уверены, что единицы являются надежными; вы можете тщательно исследовать отдельные методы с помощью множества входных данных или интересных вещей, которые не обязательно происходят во время ваших интеграционных тестов.

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

1
ответ дан 28 November 2019 в 02:16
поделиться

Вам может быть интересен этот вопрос и связанные с ним ответы . Вы можете найти мое дополнение к ответам, которые уже были даны здесь (это правильный английский? :)

1
ответ дан 28 November 2019 в 02:16
поделиться

У нас есть 4 различных типа тестов в нашем проекте:

  1. Модульные тесты с имитацией в случае необходимости
  2. Тесты БД, которые действуют аналогично модульным тестам, но затем касаются БД и очищаются
  3. ] Наша логика раскрывается через REST, поэтому у нас есть тесты, которые выполняют HTTP
  4. тесты Webapp с использованием WatiN, которые на самом деле используют экземпляр IE и проходят через основные функции

Мне нравятся модульные тесты. Они работают очень быстро (в 100-1000 раз быстрее, чем тесты № 4). Они безопасны от типов, поэтому рефакторинг довольно прост (с хорошей IDE).

Основная проблема в том, сколько работы требуется для их правильного выполнения. Вы должны издеваться над всем: доступ к БД, доступ к сети, другие компоненты. Вы должны украсить немодные классы, получая миллионы в основном бесполезных классов. Вы должны использовать DI, чтобы ваши компоненты не были тесно связаны и, следовательно, не тестировались (обратите внимание, что использование DI на самом деле не является недостатком:)

Мне нравятся тесты №2. Они используют базу данных и сообщат об ошибках базы данных, нарушениях ограничений и неверных столбцах. Я думаю, что мы получаем ценное тестирование, используя это.

№ 3 и особенно № 4 более проблематичны. Они требуют некоторого подмножества производственной среды на сервере сборки. Вы должны создать, развернуть и запустить приложение. Вы должны иметь чистую БД каждый раз. Но, в конце концов, это окупается. Тесты Watin требуют постоянной работы, но вы также получаете постоянное тестирование. Мы запускаем тесты для каждого коммита, и очень легко увидеть, когда мы что-то сломаем.

Итак, вернемся к вашему вопросу. Модульные тесты бывают быстрыми (что очень важно, время сборки должно быть меньше, скажем, 10 минут), и их легко реорганизовать. Гораздо проще, чем переписать всю вещь, если ваш дизайн меняется. Если вы используете хороший редактор с хорошей командой find usages (например, IDEA или VS.NET + Resharper), вы всегда можете найти, где тестируется ваш код.

С тестами REST / HTTP вы получите хорошая хорошая проверка того, что ваша система действительно работает. Но тесты запускаются медленно, поэтому сложно пройти полную проверку на этом уровне. Я предполагаю, что ваши методы принимают несколько параметров или, возможно, ввод XML. Чтобы проверить каждый узел в XML или каждый параметр, потребуется десятки или сотни вызовов. Вы можете сделать это с помощью модульных тестов, но вы не можете сделать это с помощью вызовов REST, когда каждый из них может занимать большую долю секунды.

Наши модульные тесты проверяют специальные граничные условия гораздо чаще, чем тесты №3. Они (# 3) проверяют, что основной функционал работает и все.

1
ответ дан 28 November 2019 в 02:16
поделиться

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

Дизайн, управляемый тестированием, используемый как средство, чтобы стать лучшим разработчиком, имеет свои достоинства, но для этого не требуется. Есть много хороших программистов, которые никогда не писали модульные тесты. Лучшая причина для модульных тестов - это возможности, которые они дают вам при рефакторинге, особенно когда многие люди меняют исходный код одновременно. Выявление ошибок при регистрации также позволяет значительно сэкономить время для проекта (подумайте о переходе на модель CI и используйте регистрацию, а не каждую ночь). Поэтому, если вы пишете модульный тест, до или после написания кода, который он тестирует, вы в этот момент уверены в новом коде, который вы написали. Это то, что может случиться с этим кодом позже, против чего гарантирует модульный тест - и это может иметь большое значение. Модульные тесты могут остановить ошибки до того, как они перейдут к контролю качества, тем самым ускоряя ваши проекты.

Интеграционные тесты нагружают интерфейсы между элементами в вашем стеке, если они выполнены правильно. По моему опыту, интеграция - самая непредсказуемая часть проекта. Заставить работать отдельные части обычно не так сложно, но собрать все вместе может быть очень сложно из-за типов ошибок, которые могут возникнуть на этом этапе. Во многих случаях проекты опаздывают из-за того, что происходит при интеграции. Некоторые из ошибок, обнаруженных на этом шаге, обнаруживаются в интерфейсах, которые были нарушены из-за некоторых изменений, внесенных на одной стороне, которые не были переданы другой стороне. Другой источник ошибок интеграции - это конфигурации, обнаруженные в dev, но забытые к тому времени, когда приложение перейдет в QA. Интеграционные тесты могут помочь значительно сократить оба типа.

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

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

С практической точки зрения, все сводится к тому, где вам больше всего нужна скорость в вашей собственной организации / процессе.

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

С практической точки зрения, все сводится к тому, где вам больше всего нужна скорость в вашей собственной организации / процессе.

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

С практической точки зрения, все сводится к тому, где вам больше всего нужна скорость в вашей собственной организации / процессе.

5
ответ дан 28 November 2019 в 02:16
поделиться
Другие вопросы по тегам:

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