Добрый день.
Раздельное тестирование зависимых компонентов предполагает наличие заглушек (stubs) на каждый из них. Рассмотрим небольшой пример: текстовый файл test.txt содержит цитаты, а скрипт first.pl выводит их в случайном порядке.
Файл test.txt:
When I can't handle events, I let them handle themselves. One of the keys to happiness is a bad memory. Science is organized knowledge. Wisdom is organized life. Reality is merely an illusion, albeit a very persistent one. Variety is the soul of pleasure.
В скрипте применяется подпрограмма shuffle из пакета List::Util стандартной библиотеки.
#!/usr/bin/perl -w use strict; use List::Util qw(shuffle); my @lines; open (FH, "test.txt") or die "Can't read this file: $!"; while (<FH>) { push(@lines, $_); } close (FH); @lines = shuffle(@lines); foreach (@lines) { print $_; }
pragma:/home/share/Work # perl first.pl Variety is the soul of pleasure. One of the keys to happiness is a bad memory. When I can't handle events, I let them handle themselves. Reality is merely an illusion, albeit a very persistent one. Science is organized knowledge. Wisdom is organized life.
Установим заглушку на подпрограмму shuffle. Пусть заглушка служит простым передатчиком: данные, поступающие на вход, без изменений передаются на выход. Воспользуемся typeglob и сделаем shuffle алиасом для подпрограммы fake.
#!/usr/bin/perl -w use strict; use List::Util qw(shuffle); my @lines; sub fake { return @_; } undef &shuffle; *shuffle = \&fake; open (FH, "test.txt") or die "Can't read this file: $!"; while (<FH>) { push(@lines, $_); } close (FH); @lines = shuffle(@lines); foreach (@lines) { print $_; }
В результате вместо подпрограммы shuffle будет выполняться подпрограмма fake, которая выдаст заранее известный результат.
pragma:/home/share/Work # perl second.pl When I can't handle events, I let them handle themselves. One of the keys to happiness is a bad memory. Science is organized knowledge. Wisdom is organized life. Reality is merely an illusion, albeit a very persistent one. Variety is the soul of pleasure.
Подобные операции можно выполнить с помощью модулей, которые, по сути, служат обертками вокруг операций с таблицей символов. К примеру, модуль Test::MockModule предоставляет возможности для гибкой подмены подпрограмм и трассировки таких операций. В скрипте third.pl подменяется и затем “восстанавливается” подпрограмма shuffle.
#!/usr/bin/perl -w use List::Util qw(shuffle); use Test::MockModule; use strict; my @lines; my $module = new Test::MockModule('List::Util'); $module->mock(shuffle => sub (@) { return @_ }); open (FH, "test.txt") or die "Can't read this file: $!"; while (<FH>) { push(@lines, $_); } close (FH); print "Mocked subroutine:\n"; @lines = List::Util::shuffle(@lines); foreach (@lines) { print $_; } print "\nOriginal subroutine:\n"; $module->unmock(shuffle); @lines = shuffle(@lines); foreach (@lines) { print $_; }
Скрипт выдаст строки сначала в исходном, а затем в произвольном порядке.
Возможности установки заглушек на классы, методы и объекты будут рассмотрены в одной из следующих статей. Оставайтесь с нами.
Что такое качество программного обеспечения и как его улучшить: теория и практика, задачи и решения, подводные камни и обходные пути.
Автор комментария : Ivanych | March 3, 2009
Хотелось бы понять, зачем вообще все это нужно.
[Ответить]
Автор комментария : Капитан Аляска | March 3, 2009
Ivanych, представьте проект, в котором трудится много программистов. Каждый из них делает какую-то маленькую часть большого продукта. Если в проекте есть практика модульного тестирования, то у отдельно взятого программиста должна быть возможность протестировать свой код – вне зависимости от такого, в каком состоянии другие компоненты продукта. Допустим, программист пишет модуль A, который зависит от модулей B и C. В этом случае программист может поставить заглушки в тех местах, где его код зависит от этих модулей.
Пример: есть продукт с GUI (графический интерфейс) и core (базовая функциональность). Если от core к GUI приходит время в диапазоне 06.00-10.00, то GUI должно выдавать “Доброе утро”. Если 10.00-19.00, то “Добрый день” и т.д. В этом случае поведение GUI можно проверить без core. В тех местах, где происходит вызов методов core, можно подставить заглушки, которые будут выдавать заранее известный результат.
[Ответить]
Автор комментария : Ivanych | March 3, 2009
Правильно ли я понимаю, что вся соль статьи заключена в конструкции “*shuffle = \&fake;”, а смысл статьи, вкратце, формулируется так:
“Чтобы не лезть далеко в код и и не переписывать вызовы функций на собственные, нужно выполнить эту конструкцию где-нибудь в начале файла, ДО вызова замещаемых функций?”
[Ответить]
Автор комментария : Капитан Аляска | March 3, 2009
Ivanych, соль статьи – это сильно сказано :) Но в целом – да. Пример иллюстрирует механизм вызова одной подпрограммы вместо другой. В роли исходной подпрограммы (в данном случае, shuffle) выступает ваша “рабочая” подпрограмма (с вашей логикой, вашим алгоритмом, вашей обработкой), а в качестве подмены выступает заглушка (в данном случае, fake), в которой нет никакой логики, а есть заранее известный результат на выходе.
Смысл статьи: функциональность интерпретатора Perl позволяет легко организовать заглушки на те или иные подпрограммы. Это удобно при модульном тестировании (unit testing). А вот как вы воспользуетесь такими возможностями, целиком зависит от вас и от тех задач, которые перед вами стоят.
[Ответить]
Pingback : OpenQuality.ru | Perl: заглушки на классы, методы и объекты | March 4, 2009
[…] также: Заглушки на подпрограммы в […]
Pingback : OpenQuality.ru | Ступень Мартина, или двойники в Python | April 11, 2009
[…] реализовать средствами самого языка (как и в случае с Perl). В качестве иллюстрации возьмем файл account.py, […]