2016-12-15 17 views
1

Что-то совершенно неясно мне о возвращаемом значении subs. Мне нравится тестировать мои модули, sub by sub и проверять, выдают ли они правильное возвращаемое значение или правильное исключение, если это возникнет.Оценка успеха/сбой подпрограммы

Например, скажем, у меня есть следующий код (X :: Аргументом :: BadFormat является обработчик исключений, полученный из Exception :: Class):

package My::Module; 

    use strict; 
    use warnings; 

    sub new{#does things unrelated to the current question} 

    sub my_sub { 
     my ($self,$possible_value) = @_; 

     if ($possible_value =~ q{\w}) { #Affect value to current object 
      $self->{field} = $possible_value; 
     }else{ #throw an exception 
      X::Argument::BadFormat->throw(
       arg    => 'possible_value', 
       expected_format => 'something that looks like a word', 
       received_value => $possible_value, 
      ); 
     } 
    } 

В тестовом файле, я буду запускать тесты таких как:

my $object = My::Module->new(); 
throws_ok(sub {$object->my_sub('*')}, 'X::Argument::BadFormat', 'Faulty value will raise an exception'); 
ok($object->my_sub('turlututu')); 

легко проверить, когда:

  • суб возвращает значение,
  • условия испытаний должны вызвать исключение,

Однако, когда я просто установить значение поля в текущем объекте, у меня нет причин возвращаться ничего.

В этом случае:

  • является простое выполнение кода достаточно, чтобы оценить выход к югу, как «истинный»?
  • Должен ли я добавить явный «return 1;» ?
  • действительно ли последний возвращает последнюю оценку, в этом случае успешность теста
  • в «если»? Что-то еще, о чем я не думал, но которое очевидно для всех?
+1

Почему бы не просто проверить, правильно ли установлен атрибут объекта через attr, или лучше, через геттер? например: 'my $ p = 'blah'; $ Obj-> my_sub ($ р); - $ obj -> {field}, $ p, "my_sub() задает поле attr ok"; ' – stevieb

+0

Действительно. Я понимаю, что я должен был сформулировать свой вопрос по-другому. Фактическая проблема заключается в том, чтобы иметь возможность оценить, правильно ли завершилась подпрограмма, а не только для полевых аффектов, но всякий раз, когда подпрограмма не должна возвращать значение. Яснее ли это? –

+0

Ох. читая вопрос, я понимаю, что нет такой вещи, как общий ответ, не так ли? Мне нужно быть явным для моего возвращаемого значения или выполнять те же действия, которые, как предполагается, должны были быть сделаны с моим объектом. –

ответ

2

Суб, который не имеет никакой необходимости возвращать значение должно заканчиваться

return; 

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

Предполагая, что вы добавить явный возврат:

Ваш throws_ok тест выглядит отлично. Затем вы должны проверить, правильно ли установлено поле. Ваш тест ok не требуется, так как ваш юзер не будет ничего возвращать.

+0

С оговоркой, хотя - иногда '$ possible_value' может быть оценено как« истина », а в других случаях - ложь. Я не уверен, что это хорошо, и, как правило, предпочитает явное возвращение. – Sobrique

+0

@Sobrique Я предпочитаю * всегда * делать явное возвращение – ysth

+0

Спасибо. Просто для того, чтобы быть ясным - и жаль, что он плотен. Если я добавлю явный retunr в конце, будет ли тест ok() равным true или я не буду использовать этот тест в любом случае? –

3

В этом случае я просто проверил, чтобы атрибут объекта был установлен правильно. Вот и все, что это делает. Если он настроен в порядке, субподрыв правильно. Если он не был установлен, что-то пошло не так, как до конца.

my $p='blah'; 
$obj->my_sub($p); 

is $obj->{field}, $p, "my_sub() set the field attr ok"; 

Было бы лучше, если атрибут field был добытчик, поэтому вы не нарушая инкапсуляцию, но я отвлекся.

+0

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

1

Perl возвращает результат последнего выполненного кода по умолчанию.

Например:

print main(); 

sub main { 
    my $var = 9 * 7; 
} 

print будет выводить 63.Если на ваш код может повлиять вывод данной подпрограммы, вам нужно установить возвращаемое значение (обычно считается, что всегда рекомендуется установить явный возврат в конце подпрограммы/метода).

print main(); 

sub main { 
    my $var = 9 * 7; 
    return; 
} 

print ничего не выдаст.

Лично я всегда стараюсь установить возвращаемое значение в зависимости от контекста того, к чему будет возвращаться подпрограмма, но если вы пишете код, который будут использовать другие люди, тогда вообще безопаснее всего делать return;.

Дополнительное объяснение из Perl :: Критика (link to the specific policy):

Subroutine "главный" не заканчивается "возвращение" в строке 8, вблизи 'суб основного {'.

Подпрограмма :: RequireFinalReturn (критичности: 4)

Требует все подпрограммы прекратить явно с одним из следующих : return', карпа 'croak', умирают', exec', выхода 'goto', or броска'.

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

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

package Password; 
    # every time the user guesses the password wrong, its value 
    # is rotated by one character 
    my $password; 
    sub set_password { 
     $password = shift; 
    } 
    sub check_password { 
     my $guess = shift; 
     if ($guess eq $password) { 
      unlock_secrets(); 
     } else { 
      $password = (substr $password, 1).(substr $password, 0, 1); 
     } 
    } 
    1; 

В этом случае последнее утверждение в check_password() является назначением. Результатом этого присвоения является неявное возвращаемое значение, поэтому ошибка возвращает правильный пароль! Добавление `return; ' в конце этого подпрограмма решает проблему.

Единственное исключение - пустая подпрограмма.

Будьте осторожны при устранении проблем, определенных настоящей Политикой; не слепо положил `return; ' в конце каждой подпрограммы.

+0

Вы должны включить ссылку для цитаты Perl :: Critic. – simbabque

+1

Я только что запустил 'perlcritic -1 --verbose 11' из моей командной строки, но вот страница cpan для модуля, это от: [Perl :: Critic :: Policy :: Subroutines :: RequireFinalReturn] (http: // search.cpan.org/~thaljef/Perl-Critic/lib/Perl/Critic/Policy/Subroutines/RequireFinalReturn.pm) – interduo