Le site Umsetzung von set_retval_scalar
mag auf den ersten Blick entmutigend erscheinen:
sub set_retval_scalar {
my $self = shift; # my blessed self
my $type = shift; # type number from --dbitest=TYPE
my $sql = shift; # SQL pattern for badness
push @{ $scalar_retval{$type} },
{ "SQL" => $sql, "retval" => $_[0] };
}
Der Grund für die erneute Verwendung des ersten Ergebnissatzes sind aufeinanderfolgende Aufrufe von set_retval_scalar
son kumulativ . Nach dem zweiten Aufruf von set_retval_scalar
Kurz vor dem zweiten Test sieht die interne Buchhaltung von Test::MockDBI so aus
[ # first resultset
{ SQL => "SELECT username ...",
retval => [{ username => '1234567' }, ...]
},
# second resultset
{ SQL => "SELECT username ...",
retval => []
}
]
Unter der Haube, wenn Ihre zweite Testabfrage SELECT username ...
, _force_retval_scalar
in Test::MockDBI durchsucht diese Datenstruktur nach der aktuell ausgeführten Abfrage und hält beim ersten gefundenen Treffer an. Beide Ergebnissätze sind mit der gleichen Abfrage verknüpft, so dass der zweite keine Chance hat, übereinzustimmen.
Aber es gibt Hoffnung! Beachten Sie, dass set_retval_scalar
kopiert nur den äußersten Verweis - einen Verweis auf ein Feld, das Sie kontrollieren!
Ändern Sie Ihren Test leicht ab:
my @usernames_many = (
{ username => '1234567' },
{ username => '2345678' },
);
my @usernames_empty = ();
my $usernames = [];
$mock_dbi->set_retval_scalar(
MOCKDBI_WILDCARD,
"SELECT username FROM location",
$usernames);
Mit dieser Vorrichtung müssen Sie nur den Inhalt von @$usernames
(d. h. das Array bezogen auf por $usernames
), um das gespeicherte Ergebnis der Abfrage zu ändern:
@$usernames = @usernames_many;
is_deeply(find_multiple_registrations($mock_db, 15),
[ '1234567', '2345678' ],
"many entries");
@$usernames = @usernames_empty;
is_deeply(find_multiple_registrations($mock_db, 15),
[ ],
"no entries");
Mit diesen Änderungen werden beide Tests bestanden.
WICHTIG! Immer zuordnen @$usernames
! Sie könnten versucht sein, ein paar Tastenanschläge zu sparen, indem Sie schreiben
$usernames = []; # empty usernames
is_deeply(find_multiple_registrations($mock_db, 15),
[ ],
"no entries");
aber dies wird dazu führen, dass Ihr Test aus fast dem gleichen Grund wie der Test aus Ihrer Frage fehlschlägt: Die Vorrichtung wird weiterhin den gleichen Verweis haben, den Sie ihr im Aufruf von set_retval_scalar
. Eine solche Vorgehensweise wäre sowohl falsch als auch irreführend - eine unangenehme Kombination.
Der Vollständigkeit halber ist unten ein vollständiges Arbeitsbeispiel aufgeführt.
#! /usr/bin/perl
use warnings;
use strict;
BEGIN { push @ARGV, "--dbitest" }
use Test::MockDBI qw/ :all /;
use Test::More tests => 2;
my @usernames_many = (
{ username => '1234567' },
{ username => '2345678' },
);
my @usernames_empty = ();
my $usernames = [];
my $mock_dbi = get_instance Test::MockDBI;
my $mock_db = DBI->connect("dbi:SQLite:dbname=:memory:", "", "");
$mock_db->{RaiseError} = 1;
$mock_db->do(q{CREATE TABLE location (username char(10))});
sub find_multiple_registrations {
my($dbh,$limit) = @_;
my $sth = $dbh->prepare("SELECT username FROM location");
$sth->execute;
[ map $_->{username} => @{ $sth->fetchall_arrayref } ];
}
$mock_dbi->set_retval_scalar(
MOCKDBI_WILDCARD,
"SELECT username FROM location",
$usernames);
@$usernames = @usernames_many;
is_deeply(find_multiple_registrations($mock_db, 15),
[ '1234567', '2345678' ],
"many entries");
@$usernames = ();
is_deeply(find_multiple_registrations($mock_db, 15),
[ ],
"no entries");
Ausgabe:
1..2
connect() 'CONNECT TO dbi:SQLite:dbname=:memory: AS WITH '
do() 'CREATE TABLE location (username char(10))'
prepare() 'SELECT username FROM location'
execute()
fetchall\_arrayref()
ok 1 - many entries
prepare() 'SELECT username FROM location'
execute()
fetchall\_arrayref()
ok 2 - no entries