Модульное тестирование

Поделись знанием:
Перейти к: навигация, поиск

Модульное тестирование, или юнит-тестирование (англ. unit testing) — процесс в программировании, позволяющий проверить на корректность отдельные модули исходного кода программы.

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





Преимущества

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

Этот тип тестирования обычно выполняется программистами.

Поощрение изменений

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

Упрощение интеграции

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

Документирование кода

Модульные тесты можно рассматривать как «живой документ» для тестируемого класса. Клиенты, которые не знают, как использовать данный класс, могут использовать юнит-тест в качестве примера.

Отделение интерфейса от реализации

Поскольку некоторые классы могут использовать другие классы, тестирование отдельного класса часто распространяется на связанные с ним. Например, класс пользуется базой данных; в ходе написания теста программист обнаруживает, что тесту приходится взаимодействовать с базой. Это ошибка, поскольку тест не должен выходить за границу класса. В результате разработчик абстрагируется от соединения с базой данных и реализует этот интерфейс, используя свой собственный mock-объект. Это приводит к менее связанному коду, минимизируя зависимости в системе.

Когда модульное тестирование не работает

Сложный код

Тестирование программного обеспечения — комбинаторная задача. Например, каждое возможное значение булевской переменной потребует двух тестов: один на вариант TRUE, другой — на вариант FALSE. В результате на каждую строку исходного кода потребуется 3−5 строк тестового кода.

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

Результат известен лишь приблизительно

Например, в математическом моделировании. Бизнес-приложения зачастую работают с конечными и счётными множествами, научные — с континуальными.[1] Поэтому сложно подобрать тесты для каждой из ветвей программы, сложно сказать, верен ли результат, выдерживается ли точность, и т. д. А во многих случаях качество моделирования определяется «на глаз», и последний результат записывается как «опорный». Если найдено расхождение, новый результат проверяют вручную и выясняют, какой качественнее: старый или новый.

Ошибки интеграции и производительности

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

При общей низкой культуре программирования

Для получения выгоды от модульного тестирования требуется строго следовать технологии тестирования на всём протяжении процесса разработки программного обеспечения. Нужно хранить не только записи обо всех проведённых тестах, но и обо всех изменениях исходного кода во всех модулях. С этой целью следует использовать систему контроля версий ПО. Таким образом, если более поздняя версия ПО не проходит тест, который был успешно пройден ранее, будет несложным сверить варианты исходного кода и устранить ошибку. Также необходимо убедиться в неизменном отслеживании и анализе неудачных тестов. Игнорирование этого требования приведёт к лавинообразному увеличению неудачных тестовых результатов.

Проблемы с объектами-заглушками

За исключением простейших случаев, тестируемый объект должен взаимодействовать с другими объектами. Этих «товарищей по взаимодействию» — объекты-заглушки — делают предельно простыми: либо крайне упрощёнными (память вместо БД), либо рассчитанными на конкретный тест и механически повторяющими сессию обмена. Вопросы начинаются, когда протокол обмена меняется; надо отыскивать эти заглушки во всех тестах и переводить под новый протокол.[2]

Приложения модульного тестирования

Экстремальное программирование

Экстремальное программирование предполагает как один из постулатов использование инструментов автоматического модульного тестирования. Этот инструментарий может быть создан либо третьей стороной (например, Boost.Test), либо группой разработчиков данного приложения.

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

Техника модульного тестирования

Инструментарий

Для большинства популярных языков программирования высокого уровня существуют инструменты и библиотеки модульного тестирования. Некоторые из них:

  • Для Java и Groovy
    • JUnit [JUnit.org/ JUnit.org]
    • TestNG [testng.org// testNG.org]
    • JavaTESK [www.unitesk.ru/content/category/5/25/60/ UniTESK.ru]
    • [spockframework.org/ Spock] (написан на Groovy)
  • Для C
    • CUnit [cunit.sourceforge.net/ cunit]
    • CTESK [www.unitesk.ru/content/category/5/13/32/ UniTESK.ru]
    • cfix [sourceforge.net/projects/cfix/ cfix]
    • [ispras.linux-foundation.org/index.php/API_Sanity_Autotest API Sanity Autotest] — для динамических C/C++ библиотек в Unix-подобных ОС.
    • Unity [sourceforge.net/projects/unity/ unity] — для встраиваемых приложений
    • MICRO_UNIT [sourceforge.net/projects/microunit/ MICRO_UNIT] — небольшой набор макросов с примерами использования.
  • Для Ruby
    • Rspec [rspec.info/]
    • Test::Unit [www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/index.html]
  • Для Objective-C
    • OCUnit [www.sente.ch/software/ocunit/]
  • Для C++
    • CxxTest [cxxtest.com/cxxtest/doc/guide.html]
    • CPPUnit [apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page]
    • Boost Test [www.boost.org/doc/libs/1_38_0/libs/test/doc/html/index.html]
    • Google C++ Testing Framework [code.google.com/p/googletest/]
    • Symbian[www.symbianosunit.co.uk/] — фреймворк для Symbian OS всех версий.
    • [ispras.linux-foundation.org/index.php/API_Sanity_Autotest API Sanity Autotest] — для динамических C/C++ библиотек в Unix-подобных ОС.
    • [qt.apidoc.info/5.2.0/qttestlib/qttest-index.html Qt Test framework] — для программ, разработанных с помощью библиотеки Qt
  • Для C#
    • Nunit [www.nunit.org/]
    • XUnit.net [xunit.codeplex.com/]
    • MbUnit [www.mbunit.com/]
  • DUnit [dunit.sourceforge.net/] — для Delphi
  • EUnit [svn.process-one.net/contribs/trunk/eunit/doc/overview-summary.html] — Erlang
  • Для Perl
    • Test [search.cpan.org/perldoc?Test]
    • Test::Simple [search.cpan.org/perldoc?Test::Simple]
    • Test::More [search.cpan.org/perldoc?Test::More]
    • Test::Unit [search.cpan.org/perldoc?Test::Unit]
    • Test::Unit::Lite [search.cpan.org/perldoc?Test::Unit::Lite]
  • Для PHP
  • Для Python
    • PyUnit [en.wikipedia.org/wiki/PyUnit]
    • PyTest [codespeak.net/py]
    • Nose [somethingaboutorange.com/mrl/projects/nose/]
  • vbUnit [vbunit.com/] — Visual Basic
  • utPLSQL [utplsql.sourceforge.net/] — PL/SQL
  • Для T-SQL
    • TSQLUnit [sourceforge.net/apps/trac/tsqlunit/]
    • SPUnit [spunit.sourceforge.net/]
  • Для ActionScript 2.0 — язык сценариев, используемый виртуальной машиной Adobe Flash Player версии 7 и 8
    • AsUnit [asunit.sourceforge.net/]
    • AS2Unit [www.as2unit.org/]
  • Для ActionScript 3.0 — скриптовый язык, используемый виртуальной машиной Adobe Flash Player версии 9 и выше
    • FlexUnit [opensource.adobe.com/wiki/display/flexunit/]
    • AsUnit [asunit.org/]
  • Для JavaScript
    • Mocha (тестовый фреймворк) [mochajs.org]
    • Chai («assertion library», используется совместно с тестовым framework’ом) [chaijs.com/]
    • Sinon.JS (библиотека для создания mock’ов, stub’ов, spy’ев, используется совместо с тестовым framework’ом) [sinonjs.org/]
    • Karma runner (от создателей Angular.JS, «test runner» — организует среду выполнения тестов) [karma-runner.github.io/]
    • QUnit (от создателей jQuery) [qunitjs.com/]
    • JsUnit (больше не поддерживается создателями) [www.jsunit.net/]
    • Jasmine (рекомендован создателями jsUnit) [pivotal.github.com/jasmine/]
    • D.O.H [www.dojotoolkit.org/reference-guide/util/doh.html]

Поддержка на уровне языка

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

Пример таких языков:

Пример кода на языке D

class ABC
{
    this() { val = 2; }

    private int val;
    public func() { val *= 2; }
}

unittest
{
   ABC a;
   a.func();

   assert( a.val > 0 && a.val < 555 ); // можно обратиться к приватной переменной внутри модуля
}

Примеры

Java

public class TestAdder {
    public void testSum() {
        Adder adder = new AdderImpl();
        // can it add positive numbers?
        assert(adder.add(1, 1) == 2);
        assert(adder.add(1, 2) == 3);
        assert(adder.add(2, 2) == 4);
        // is zero neutral?
        assert(adder.add(0, 0) == 0);
        // can it add negative numbers?
        assert(adder.add(-1, -2) == -3);
        // can it add a positive and a negative?
        assert(adder.add(-1, 1) == 0);
        // how about larger numbers?
        assert(adder.add(1234, 988) == 2222);
    }
}

Напишите отзыв о статье "Модульное тестирование"

Примечания

  1. [habrahabr.ru/post/92038/ Почему юнит-тесты не работают в научных приложениях / Хабрахабр]
  2. [habrahabr.ru/post/275249/ Проблема дублирования и устаревания знания в mock-объектах или Интеграционные тесты — это хорошо / Хабрахабр]

См. также

Ссылки

Сайты и ресурсы
  • [openquality.ru/software-testing/unit-tests.php Тестирование программного обеспечения: модульные тесты] — коллекция статей на сайте OpenQuality.ru  (рус.)
  • [ArtOfUnitTesting.com/ The Art Of Unit Testing]  (англ.)
Статьи
  • [rsdn.ru/article/testing/UnitTesting.xml Модульное тестирование: 2+2 = 4?]  (рус.)
  • [software-testing.ru/library/testing/general-testing/77-2008-09-29-07-30-13 Модульное тестирование. Зачем, как и кто]  (рус.)
  • [weblogs.asp.net/rosherove/archive/2008/01/17/the-evolution-of-unit-testing-and-syntax.aspx The evolution of Unit Testing Syntax and Semantics]  (англ.)
  • [geosoft.no/development/unittesting.html Unit Testing Guidelines from GeoSoft]  (англ.)


Отрывок, характеризующий Модульное тестирование

«7 го декабря.
«Видел сон, будто Иосиф Алексеевич в моем доме сидит, я рад очень, и желаю угостить его. Будто я с посторонними неумолчно болтаю и вдруг вспомнил, что это ему не может нравиться, и желаю к нему приблизиться и его обнять. Но только что приблизился, вижу, что лицо его преобразилось, стало молодое, и он мне тихо что то говорит из ученья Ордена, так тихо, что я не могу расслышать. Потом, будто, вышли мы все из комнаты, и что то тут случилось мудреное. Мы сидели или лежали на полу. Он мне что то говорил. А мне будто захотелось показать ему свою чувствительность и я, не вслушиваясь в его речи, стал себе воображать состояние своего внутреннего человека и осенившую меня милость Божию. И появились у меня слезы на глазах, и я был доволен, что он это приметил. Но он взглянул на меня с досадой и вскочил, пресекши свой разговор. Я обробел и спросил, не ко мне ли сказанное относилось; но он ничего не отвечал, показал мне ласковый вид, и после вдруг очутились мы в спальне моей, где стоит двойная кровать. Он лег на нее на край, и я будто пылал к нему желанием ласкаться и прилечь тут же. И он будто у меня спрашивает: „Скажите по правде, какое вы имеете главное пристрастие? Узнали ли вы его? Я думаю, что вы уже его узнали“. Я, смутившись сим вопросом, отвечал, что лень мое главное пристрастие. Он недоверчиво покачал головой. И я ему, еще более смутившись, отвечал, что я, хотя и живу с женою, по его совету, но не как муж жены своей. На это он возразил, что не должно жену лишать своей ласки, дал чувствовать, что в этом была моя обязанность. Но я отвечал, что я стыжусь этого, и вдруг всё скрылось. И я проснулся, и нашел в мыслях своих текст Св. Писания: Живот бе свет человеком, и свет во тме светит и тма его не объят . Лицо у Иосифа Алексеевича было моложавое и светлое. В этот день получил письмо от благодетеля, в котором он пишет об обязанностях супружества».
«9 го декабря.
«Видел сон, от которого проснулся с трепещущимся сердцем. Видел, будто я в Москве, в своем доме, в большой диванной, и из гостиной выходит Иосиф Алексеевич. Будто я тотчас узнал, что с ним уже совершился процесс возрождения, и бросился ему на встречу. Я будто его целую, и руки его, а он говорит: „Приметил ли ты, что у меня лицо другое?“ Я посмотрел на него, продолжая держать его в своих объятиях, и будто вижу, что лицо его молодое, но волос на голове нет, и черты совершенно другие. И будто я ему говорю: „Я бы вас узнал, ежели бы случайно с вами встретился“, и думаю между тем: „Правду ли я сказал?“ И вдруг вижу, что он лежит как труп мертвый; потом понемногу пришел в себя и вошел со мной в большой кабинет, держа большую книгу, писанную, в александрийский лист. И будто я говорю: „это я написал“. И он ответил мне наклонением головы. Я открыл книгу, и в книге этой на всех страницах прекрасно нарисовано. И я будто знаю, что эти картины представляют любовные похождения души с ее возлюбленным. И на страницах будто я вижу прекрасное изображение девицы в прозрачной одежде и с прозрачным телом, возлетающей к облакам. И будто я знаю, что эта девица есть ничто иное, как изображение Песни песней. И будто я, глядя на эти рисунки, чувствую, что я делаю дурно, и не могу оторваться от них. Господи, помоги мне! Боже мой, если это оставление Тобою меня есть действие Твое, то да будет воля Твоя; но ежели же я сам причинил сие, то научи меня, что мне делать. Я погибну от своей развратности, буде Ты меня вовсе оставишь».


Денежные дела Ростовых не поправились в продолжение двух лет, которые они пробыли в деревне.
Несмотря на то, что Николай Ростов, твердо держась своего намерения, продолжал темно служить в глухом полку, расходуя сравнительно мало денег, ход жизни в Отрадном был таков, и в особенности Митенька так вел дела, что долги неудержимо росли с каждым годом. Единственная помощь, которая очевидно представлялась старому графу, это была служба, и он приехал в Петербург искать места; искать места и вместе с тем, как он говорил, в последний раз потешить девчат.
Вскоре после приезда Ростовых в Петербург, Берг сделал предложение Вере, и предложение его было принято.
Несмотря на то, что в Москве Ростовы принадлежали к высшему обществу, сами того не зная и не думая о том, к какому они принадлежали обществу, в Петербурге общество их было смешанное и неопределенное. В Петербурге они были провинциалы, до которых не спускались те самые люди, которых, не спрашивая их к какому они принадлежат обществу, в Москве кормили Ростовы.
Ростовы в Петербурге жили так же гостеприимно, как и в Москве, и на их ужинах сходились самые разнообразные лица: соседи по Отрадному, старые небогатые помещики с дочерьми и фрейлина Перонская, Пьер Безухов и сын уездного почтмейстера, служивший в Петербурге. Из мужчин домашними людьми в доме Ростовых в Петербурге очень скоро сделались Борис, Пьер, которого, встретив на улице, затащил к себе старый граф, и Берг, который целые дни проводил у Ростовых и оказывал старшей графине Вере такое внимание, которое может оказывать молодой человек, намеревающийся сделать предложение.
Берг недаром показывал всем свою раненую в Аустерлицком сражении правую руку и держал совершенно не нужную шпагу в левой. Он так упорно и с такою значительностью рассказывал всем это событие, что все поверили в целесообразность и достоинство этого поступка, и Берг получил за Аустерлиц две награды.
В Финляндской войне ему удалось также отличиться. Он поднял осколок гранаты, которым был убит адъютант подле главнокомандующего и поднес начальнику этот осколок. Так же как и после Аустерлица, он так долго и упорно рассказывал всем про это событие, что все поверили тоже, что надо было это сделать, и за Финляндскую войну Берг получил две награды. В 19 м году он был капитан гвардии с орденами и занимал в Петербурге какие то особенные выгодные места.
Хотя некоторые вольнодумцы и улыбались, когда им говорили про достоинства Берга, нельзя было не согласиться, что Берг был исправный, храбрый офицер, на отличном счету у начальства, и нравственный молодой человек с блестящей карьерой впереди и даже прочным положением в обществе.
Четыре года тому назад, встретившись в партере московского театра с товарищем немцем, Берг указал ему на Веру Ростову и по немецки сказал: «Das soll mein Weib werden», [Она должна быть моей женой,] и с той минуты решил жениться на ней. Теперь, в Петербурге, сообразив положение Ростовых и свое, он решил, что пришло время, и сделал предложение.
Предложение Берга было принято сначала с нелестным для него недоумением. Сначала представилось странно, что сын темного, лифляндского дворянина делает предложение графине Ростовой; но главное свойство характера Берга состояло в таком наивном и добродушном эгоизме, что невольно Ростовы подумали, что это будет хорошо, ежели он сам так твердо убежден, что это хорошо и даже очень хорошо. Притом же дела Ростовых были очень расстроены, чего не мог не знать жених, а главное, Вере было 24 года, она выезжала везде, и, несмотря на то, что она несомненно была хороша и рассудительна, до сих пор никто никогда ей не сделал предложения. Согласие было дано.
– Вот видите ли, – говорил Берг своему товарищу, которого он называл другом только потому, что он знал, что у всех людей бывают друзья. – Вот видите ли, я всё это сообразил, и я бы не женился, ежели бы не обдумал всего, и это почему нибудь было бы неудобно. А теперь напротив, папенька и маменька мои теперь обеспечены, я им устроил эту аренду в Остзейском крае, а мне прожить можно в Петербурге при моем жалованьи, при ее состоянии и при моей аккуратности. Прожить можно хорошо. Я не из за денег женюсь, я считаю это неблагородно, но надо, чтоб жена принесла свое, а муж свое. У меня служба – у нее связи и маленькие средства. Это в наше время что нибудь такое значит, не так ли? А главное она прекрасная, почтенная девушка и любит меня…
Берг покраснел и улыбнулся.
– И я люблю ее, потому что у нее характер рассудительный – очень хороший. Вот другая ее сестра – одной фамилии, а совсем другое, и неприятный характер, и ума нет того, и эдакое, знаете?… Неприятно… А моя невеста… Вот будете приходить к нам… – продолжал Берг, он хотел сказать обедать, но раздумал и сказал: «чай пить», и, проткнув его быстро языком, выпустил круглое, маленькое колечко табачного дыма, олицетворявшее вполне его мечты о счастьи.
Подле первого чувства недоуменья, возбужденного в родителях предложением Берга, в семействе водворилась обычная в таких случаях праздничность и радость, но радость была не искренняя, а внешняя. В чувствах родных относительно этой свадьбы были заметны замешательство и стыдливость. Как будто им совестно было теперь за то, что они мало любили Веру, и теперь так охотно сбывали ее с рук. Больше всех смущен был старый граф. Он вероятно не умел бы назвать того, что было причиной его смущенья, а причина эта была его денежные дела. Он решительно не знал, что у него есть, сколько у него долгов и что он в состоянии будет дать в приданое Вере. Когда родились дочери, каждой было назначено по 300 душ в приданое; но одна из этих деревень была уж продана, другая заложена и так просрочена, что должна была продаваться, поэтому отдать имение было невозможно. Денег тоже не было.
Берг уже более месяца был женихом и только неделя оставалась до свадьбы, а граф еще не решил с собой вопроса о приданом и не говорил об этом с женою. Граф то хотел отделить Вере рязанское именье, то хотел продать лес, то занять денег под вексель. За несколько дней до свадьбы Берг вошел рано утром в кабинет к графу и с приятной улыбкой почтительно попросил будущего тестя объявить ему, что будет дано за графиней Верой. Граф так смутился при этом давно предчувствуемом вопросе, что сказал необдуманно первое, что пришло ему в голову.
– Люблю, что позаботился, люблю, останешься доволен…