问题
I am writing a P4Perl script to make connection to a Perforce server and to automate execution of Perforce commands. Along with the development of the subroutines to access Perforce, I am also developing unit tests to verify the them. I am new to both Perl and unit testing.
This is my subroutine to establish a connection to Perforce. Filename is p4_connect.pl
use warnings;
use strict;
use P4;
my $clientname = "johndoe"
my $p4port = "icmanage:1667"
main();
sub main {
my $status;
$status = connect_perforce($clientname, $p4port);
};
sub connect_perforce {
my ($clientname, $p4port) = @_;
my $status;
my $p4 = new P4;
$p4->SetClient( $clientname );
$p4->SetPort( $p4port );
$status = $p4->Connect() or die( "Failed to connect to Perforce Server" );
return $status;
}
The Perl script executes fine when I run "perl p4_connect.pl"
, no errors are thrown.
However, when I moved the connect_perforce
subroutine to a package module (Perforce.pm)
and wrote a unit test (perforce.t)
for it, I encountered these errors:
username@hostname% perl -Ilib t/perforce.t
ok 1 - use Perforce;
ok 2 - Perforce->can('connect_perforce')
Connect to server failed; check $P4PORT.
TCP connect to johndoe failed.
Servname not supported for ai_socktype
Failed to connect to Perforce Server at lib/Perforce.pm line 16.
This is how the unit test (perforce.t)
looks like:
use Perforce;
use warnings;
use strict;
use Test::More qw(no_plan);
use P4;
BEGIN { use_ok('Perforce'); } #package can be loaded
can_ok('Perforce', 'connect_perforce'); #subroutine connect_perforce exists
my $p4port = "icmanage:1667";
my $p4 = Perforce->connect_perforce(qw(johndoe $p4port)); #accessing the connect_perforce() subroutine
And this is how the my package (Perforce.pm)
looks like:
package Perforce;
use warnings;
use strict;
use P4;
sub connect_perforce {
my ($clientname, $p4port) = @_;
my $status;
my $p4 = new P4;
$p4->SetClient( $clientname );
$p4->SetPort( $p4port );
$status = $p4->Connect() or die( "Failed to connect to Perforce Server" );
return $status;
}
Where did I go wrong regarding my unit test? Any suggestions are helpful.
回答1:
You are mixing object orientated Perl and functional Perl, and you have fallen victim to it.
When you call a function as a method with the arrow operator ->
, Perl passes the thing on the left hand side as the first argument to the function1. In case of a package name, that's just the package name.
package Foo;
sub frobnicate{ print "@_" }
package main;
Foo->frobnicate(1, 2, 3);
The output of this will be
Foo 1 2 3
So in your case, connect_perforce
will get this assignment:
my ($clientname, $p4port) = ('Perforce', 'johndoe', 'icmanage:1667' );
So the variables will have these values:
$clientname: 'Perforce'
$p4port: 'johndoe'
And your 'icmanage:1667'
string gets lost.
When you don't have objects, don't use the arrow. The correct way to call this function (it's not a method!) is to use the fully qualified name including the package.
my $p4 = Perforce::connect_perforce('johndoe', $p4port);
I've removed this rather weird qw()
. It would give you a literal $p4port
instead of the value, so that was another bug which you would have encountered next.
Since we have established that you don't have a class, but rather a module, you also don't want to use can_ok
. That's not the right kind of test for your use case. Instead, simply call the function like I showed above, and then do useful tests with the returned value. If the function isn't there, the test program will fail, and you'll notice.
BEGIN { use_ok('Perforce'); }
my $p4 = Perforce::connect_perforce('johndoe', 'icmanage:1667');
isa_ok($p4, 'P4'); # I guess..
For more information on object orientation and on modules, take a look at perlobj and perlootut, perlnewmod and Exporter. Perlmaven has some good articles too.
1) It does more, but that's not relevant here
来源:https://stackoverflow.com/questions/43600239/perl-unit-test-for-connection-to-perforce-connect-to-server-failed-check-p4