Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The <a href="http://cpansearch.perl.org/src/AFF/Test-MockDBI-0.64/lib/Test/MockDBI.pm" rel="nofollow noreferrer">implementation of <code>set_retval_scalar</code></a> may at first appear discouraging:</p> <pre><code>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" =&gt; $sql, "retval" =&gt; $_[0] }; } </code></pre> <p>The reason the first resultset appeared to be used again is successive calls to <code>set_retval_scalar</code> are <em>cumulative</em>. After the second call to <code>set_retval_scalar</code>, just before the second test, the internal bookkeeping for Test::MockDBI resembles</p> <pre><code>[ # first resultset { SQL =&gt; "SELECT username ...", retval =&gt; [{ username =&gt; '1234567' }, ...] }, # second resultset { SQL =&gt; "SELECT username ...", retval =&gt; [] } ] </code></pre> <p>Under the hood when your second test queries <code>SELECT username ...</code>, <code>_force_retval_scalar</code> in Test::MockDBI searches this data structure for the currently executing query and stops on the first hit it finds. Both resultsets are associated with the same query, so the second doesn't have a chance to match.</p> <p>But there's hope! Notice that <code>set_retval_scalar</code> copies only the outermost reference—a reference to <em>an array that you control!</em></p> <p>Modify your test slightly:</p> <pre><code>my @usernames_many = ( { username =&gt; '1234567' }, { username =&gt; '2345678' }, ); my @usernames_empty = (); my $usernames = []; $mock_dbi-&gt;set_retval_scalar( MOCKDBI_WILDCARD, "SELECT username FROM location", $usernames); </code></pre> <p>With this fixture, you need only change the contents of <code>@$usernames</code> (that is, the array <em>referred to</em> by <code>$usernames</code>) to change the canned result of the query:</p> <pre><code>@$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"); </code></pre> <p>With these modifications, both tests pass.</p> <p><strong>IMPORTANT:</strong> Always assign to <code>@$usernames</code>! You may be tempted to save a few keystrokes by writing</p> <pre><code>$usernames = []; # empty usernames is_deeply(find_multiple_registrations($mock_db, 15), [ ], "no entries"); </code></pre> <p>but this will cause your test to fail for nearly the same reason as the test from your question: the fixture will continue to have the same reference that you gave it in the call to <code>set_retval_scalar</code>. Doing it this way would be both incorrect and misleading, a nasty combination.</p> <hr> <p>For completeness, a full working example is below.</p> <pre><code>#! /usr/bin/perl use warnings; use strict; BEGIN { push @ARGV, "--dbitest" } use Test::MockDBI qw/ :all /; use Test::More tests =&gt; 2; my @usernames_many = ( { username =&gt; '1234567' }, { username =&gt; '2345678' }, ); my @usernames_empty = (); my $usernames = []; my $mock_dbi = get_instance Test::MockDBI; my $mock_db = DBI-&gt;connect("dbi:SQLite:dbname=:memory:", "", ""); $mock_db-&gt;{RaiseError} = 1; $mock_db-&gt;do(q{CREATE TABLE location (username char(10))}); sub find_multiple_registrations { my($dbh,$limit) = @_; my $sth = $dbh-&gt;prepare("SELECT username FROM location"); $sth-&gt;execute; [ map $_-&gt;{username} =&gt; @{ $sth-&gt;fetchall_arrayref } ]; } $mock_dbi-&gt;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"); </code></pre> <p>Output:</p> <pre>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</pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload