保存命令组以供以后在perl脚本中使用

时间:2014-01-16 19:44:54

标签: perl selenium selenium-webdriver www-mechanize

我正在处理我的第一个Perl脚本,并尝试通过重复使用代码而不是一遍又一遍地使用相同的代码来尽可能高效。我已经尝试过几种不同的东西但无济于事。

我也试图避免只从外部文件导入命令集,但它现在看起来是唯一可行的选项。所以我在这里寻求建议。

这是脚本的要点(利用Selenium):

#!/usr/bin/perl
use strict;
use warnings;

use Getopt::Long;
use WWW::Selenium;

my @changepass;
my $addsub     = '';
my $add2sub    = '';

GetOptions (
    "changepass|cp=s{3}" => \@changepass,
    "addsub|as=s" => \$addsub,
    "add2sub|a2s=s" => \$add2sub,
    "help|h" => \&do_help
) or die(&do_help);


sub login {
  my $sel = WWW::Selenium->new(
      host => "localhost",
      port => 4444,
      browser => "*googlechrome",
      browser_url => "example.com",
  );
  $sel->start;
  $sel->open("/login.php");
  $sel->wait_for_page_to_load("5000");
  $sel->type("id=loginSection-username", "username");
  $sel->type("id=loginSection-password", "password");
  $sel->click("name=send");
  $sel->wait_for_page_to_load("30000");
  sleep(2);

  return $sel;
}


sub do_changepass {
  my $email = $changepass[0];
  my $oldpass = $changepass[1];
  my $newpass = $changepass[2];
  my ($sel) = @_;
  $sel->click("css=#my-webspaces-container .more > a");
  $sel->wait_for_page_to_load("30000");
  ...MORE COMMANDS...
}


if (@changepass) {
  print "Changing password...\n";
  my $sel = do_changepass();
  print "Finished!\n";
}

所以我希望能够重用某些代码块,例如my $sel变量。但我确实意识到这是一个对象。如果我能以某种方式将其存储为纯文本,然后将其导入到函数中。 (如果可能的话,不要通过外部文件。)

3 个答案:

答案 0 :(得分:3)

请注意,您应该永远将原型放在Perl子例程上(子例程标识符后面的())。您还必须始终use strictuse warnings添加到每个计划的顶部。 (use warnings优于shebang行中的-w。)

您可以在一个子例程中返回您创建的$sel对象,并在另一个子例程中进一步使用它。目前尚不清楚你想要做什么样的事情,因为你的两个子程序看起来除了在第二个结尾处的评论时是相同的,但这可能会有所帮助

#!/usr/bin/perl
use strict;
use warnings;

use WWW::Selenium;

sub login {
  my $sel = WWW::Selenium->new(
      host => "localhost",
      port => 4444,
      browser => "*googlechrome",
      browser_url => "example.com",
  );
  $sel->start;
  $sel->open("/login.php");
  $sel->wait_for_page_to_load("5000");
  $sel->type("id=username", "usernamehere");
  $sel->type("id=password", "passwordhere");
  $sel->click("name=send");
  $sel->wait_for_page_to_load("30000");
  sleep(2);

  return $sel;
}

sub some_function {
  my ($sel) = @_;
  # ....MORE COMMANDS HERE....
}

my $sel = login();
some_function($sel);

<强>更新

您的代码错误之处在于您从不致电login。如果您查看上面的示例,则会调用login来执行登录并返回$sel的值,然后将其传递给some_function

您的代码应如下所示

if (@changepass) {
  print "Changing password...\n";
  my $sel = login();
  do_changepass($sel);
  print "Finished!\n";
}

我还建议您避免在每个子例程中调用login。最好从上面调用do_changepass等的相同代码调用。

答案 1 :(得分:0)

要完成你想要完成的工作,你必须要关注$ sel对象的范围:

...

if (@commands){
    my $sel = login();
    do_changepass($sel);
}

sub login {
    my $sel = WWW::Selenium->new( host => "localhost",
                                  port => 4444,
                                  browser => "*googlechrome",
                                  browser_url => "example.com",
                                );
    $sel->start;
    $sel->open("/login.php");
    $sel->wait_for_page_to_load("5000");
    $sel->type("id=loginSection-username", "username");
    $sel->type("id=loginSection-password", "password");
    $sel->click("name=send");
    $sel->wait_for_page_to_load("30000");
    sleep(2);

    return $sel;
}

sub do_changepass {
    my $email = $changepass[0]; my $oldpass = $changepass[1]; my $newpass = $changepass[2];
    my ($sel) = @_;
    $sel->click("css=#my-webspaces-container .more > a");
    $sel->wait_for_page_to_load("30000");
    ...MORE COMMANDS...
}
...

my创建具有词法范围的变量,因此在离开当前块后它将消失(并且没有对它的引用)。

或者您可以直接在login

中使用do_changepass - 子例程
...
    sub do_changepass {
        my $email = $changepass[0]; my $oldpass = $changepass[1]; my $newpass = $changepass[2];
        my ($sel) = login(); # <--- login used here!!!
        $sel->click("css=#my-webspaces-container .more > a");
        $sel->wait_for_page_to_load("30000");
        ...MORE COMMANDS...
    }
...

答案 2 :(得分:0)

根据我的经验,为避免重复以及提高可维护性,您可以做的最好的事情之一就是引入抽象。

为了重复使用&#34; selenium&#34;整个脚本中的实例就是我所做的:

在我的测试脚本中:

my $driver = Custom::WebApp::setup_selenium( undef, undef, \%desired_capabilities );

在我的WebApp.pm中:

sub setup_selenium {

    my $self         = shift;
    my $browser      = shift;
    my $capabilities = shift;
    my $driver;
    my %desired_capabilities;

    if ($capabilities) {
        %desired_capabilities = %$capabilities;
    }

    # Start selenium with capabilities if passed in from test script
    unless ( keys %desired_capabilities == 0 ) {

        $driver = eval {
            Selenium::Remote::Driver->new(%desired_capabilities);
        };
        return $@ if $@;    # Return with error if capability not matched
    }

    # Or just start it with default settings
    else {
        $driver = eval {
            Selenium::Remote::Driver->new( browser_name => $browser,
                                           proxy => { proxyType => 'system' } );
        };
        return $@ if $@;    # Return with error if capability not matched
    }
    return $driver;

}

然后可以在整个脚本中使用setup_selenium返回的驱动程序,直到您致电$driver->quit;

如果您注意到,上面的解决方案是使用Selenium :: Remote :: Driver绑定,但如果您愿意,可以轻松替换WWW :: Selenium(虽然我建议S:R:D主要是因为它积极主动坚持Git和CPAN)。