Возможно ли использовать или требовать Perl script без выполнения его инструкций?
Мне нужно добавить модульное тестирование к некоторым старым скриптам, скрипты в основном в следующей форме:
#!/usr/bin/perl
# Main code
foo();
bar();
# subs
sub foo {
}
sub bar {
}
Если я попробую "потребовать" этот код в unit test, будет выполняться основной раздел кода, где, как я хочу, можно просто протестировать "foo" в изоляции.
Есть ли способ сделать это без перемещения foo, bar в отдельный файл .pm?
Ответы
Ответ 1
Другим распространенным трюком для сценариев модульного тестирования является обертывание тела их кода в блок "вызывающего":
#!/usr/bin/perl
use strict;
use warnings;
unless (caller) {
# startup code
}
sub foo { ... }
При запуске из командной строки cron, bash script и т.д., он работает нормально. Однако, если вы загрузите его из другой программы Perl, код "if (caller) {...}" не будет запущен. Затем в вашей тестовой программе объявите пространство имен (поскольку script, вероятно, работает в основном пакете::) и "do" script.
#!/usr/bin/perl
package Tests::Script; # avoid the Test:: namespace to avoid conflicts
# with testing modules
use strict;
use warnings;
do 'some_script' or die "Cannot (do 'some_script'): $!";
# write your tests
'do' более эффективен, чем eval, и достаточно чист для этого.
Другим трюком для тестирования скриптов является использование Expect. Это чище, но также сложнее использовать, и он не позволит вам переопределить что-либо в script, если вам нужно что-то придумать.
Ответ 2
Предполагая, что у вас нет проблем с безопасностью, оберните его в sub {...} и оцените его:
use File::Slurp "read_file";
eval "package Script; sub {" . read_file("script") . "}";
is(Script::foo(), "foo");
(заботясь о том, что eval не распространяется на любые лексики, которые были бы закрыты script).
Ответ 3
Ahh, старый вопрос "как мне unit test программа". Самый простой трюк заключается в том, чтобы поместить это в вашу программу, прежде чем он начнет делать вещи:
return 1 unless $0 eq __FILE__;
__FILE__
- текущий исходный файл. $0
- имя запускаемой программы. Если они совпадают, ваш код выполняется как программа. Если они разные, они загружаются как библиотека.
Достаточно, чтобы вы начали модульное тестирование подпрограмм внутри вашей программы.
require "some/program";
...and test...
Следующий шаг - переместить весь код вне подпрограммы в main
, тогда вы можете сделать это:
main() if $0 eq __FILE__;
и теперь вы можете протестировать main() так же, как и любую другую подпрограмму.
После этого вы можете начать созерцать перемещение программных подпрограмм в свои собственные библиотеки.