Как я могу запретить Perl использовать модуль для тестирования? - PullRequest
5 голосов
/ 11 октября 2010

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

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

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

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

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

Кто-нибудь знает, как я могу сказать Perl: «Не находите этот модуль там, где я пытаюсь« использовать »или« требовать »его для целей тестирования»?

Я использую Perl 5.10.0 (в Fedora 12) и использую Test :: More и TAP :: Harness. Некоторые из наших установок работают на Perl 5.8, поэтому я готов использовать функции 5.10 при тестировании, но не в самом коде.

Ответы [ 2 ]

11 голосов
/ 11 октября 2010

Пара модулей CPAN делает именно это. Я часто использую Test::Without::Module. Еще один будет Devel::Hide. Эти двое и несколько других, чьи имена я не могу вспомнить прямо сейчас, работают почти одинаково, подключаясь к загрузке модуля perl через @INC или CORE::GLOBAL::require. Подробности этого документированы в perldoc -f require.

4 голосов
/ 11 октября 2010

Как сказал rafl, для этого есть модули.

Если вам интересна и его механика (помимо достижения результата), есть 2 способа сделать это:

  1. Удалить модуль из пространства имен после его загрузки. Test :: Without :: Module делает это - взгляните на исходный код для деталей.

  2. Во-первых, предотвратить загрузку модуля. Самый простой подход для этого - использовать возможность Perl иметь подпрограммы как часть массива @INC, который используется при загрузке модулей через use / require. Теория, лежащая в основе этого, может быть основана в require's perldoc - искать в тексте слово «hooks».

Ссылки на подпрограммы - самые простые дело. Когда включается система включения через @INC и встречает подпрограмма, эта подпрограмма получает вызывается с двумя параметрами, первый ссылка на себя, а вторая имя файла, который будет включен (например, "Foo / Bar.pm"). Подпрограмма должен вернуть либо ничего, либо список до трех значений ...

... 2. Ссылка на подпрограмму. Если дескриптор файла (предыдущий элемент) отсутствует, то ожидается, что эта подпрограмма сгенерирует одну строку исходного кода на вызов, записывает строку в $ _ и возвращает 1, а затем возвращает 0 в конце файла.

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

# The following code was not tested - for illustrative purposes only
# MUST be done in the BEGIN block at the very beginning of the test
# BEFORE any "use Module"; lines
push @INC, \&my_sub; 
my %prohibited_module_files = map { $_=> 1} ("Foo/Bar.pm", "x.pm");
                              # Ideally, translate module names into file names
sub empty_module_sub {
    $_ = "1;\n"; # Empty module
    return 0; # End of file
}
sub my_sub {
    my ($coderef, $filename) = @_; # $coderef is \&my_sub
    if ($prohibited_modules{$filename}) {
        print STDERR "NOT loading module $filename - prohibited!\n";
        # Optionally, die here to simulate not finding the module!!!
        # Otherwise, load empty package
        return (undef, \&empty_module_sub);
    }
    return undef; # Continue searching @INC for good modules.
}

Немного более простой (но не настолько интересный или гибкий) подход будет опираться на тот факт, что семантика «требуют» сначала проверяет $INC{$filename} и, если этот ключ существует в хеше% INC, считает модуль загруженным; если ключ сопоставлен с истинным значением, он считает, что модуль уже был правильно загружен, а ложное значение умирает с ошибкой типа «ошибка компиляции». Таким образом, вы можете получить результат, аналогичный приведенному выше пользовательскому подпрограмме, вставляя значения undef или 1 под соответствующим ключом (имя файла, совпадающее с именем модуля) в %INC в блоке BEGIN в начале кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...