Подтвердить что ты не робот

Возможно ли использовать или требовать Perl script без выполнения его инструкций?

Мне нужно добавить модульное тестирование к некоторым старым скриптам, скрипты в основном в следующей форме:

#!/usr/bin/perl

# Main code
foo();
bar();

# subs
sub foo {

}
sub bar {

}

Если я попробую "потребовать" этот код в unit test, будет выполняться основной раздел кода, где, как я хочу, можно просто протестировать "foo" в изоляции.

Есть ли способ сделать это без перемещения foo, bar в отдельный файл .pm?

4b9b3361

Ответ 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() так же, как и любую другую подпрограмму.

После этого вы можете начать созерцать перемещение программных подпрограмм в свои собственные библиотеки.