I’m trying to test some code in different situations (for different result sets). I’ve got the first test running well, but the next one is trying to reuse the first “table”.
My result sets:
my $usernames_many = [
{ username => '1234567' },
{ username => '2345678' },
];
my $usernames_empty = [
];
but now when I try these calls:
$mock_dbi->set_retval_scalar(MOCKDBI_WILDCARD, "SELECT username FROM location", $usernames_many);
is_deeply(find_multiple_registrations($mock_db, 15), [ '1234567', '2345678' ], "many entries");
$mock_dbi->set_retval_scalar(MOCKDBI_WILDCARD, "SELECT username FROM location", $usernames_empty);
is_deeply(find_multiple_registrations($mock_db, 15), [ ], "no entries");
The first test passes, but the second one results in:
not ok 3 - no entries
# Failed test 'no entries'
# at ./report_many_registrations_test.pl line 28.
# Structures begin differing at:
# $got->[0] = '1234567'
# $expected->[0] = Does not exist
Which seems to indicate the first resultset was used again instead. How can I clean a resultset? Or reset the state in some other way?
The implementation of
set_retval_scalarmay at first appear discouraging:The reason the first resultset appeared to be used again is successive calls to
set_retval_scalarare cumulative. After the second call toset_retval_scalar, just before the second test, the internal bookkeeping for Test::MockDBI resemblesUnder the hood when your second test queries
SELECT username ...,_force_retval_scalarin 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.But there’s hope! Notice that
set_retval_scalarcopies only the outermost reference—a reference to an array that you control!Modify your test slightly:
With this fixture, you need only change the contents of
@$usernames(that is, the array referred to by$usernames) to change the canned result of the query:With these modifications, both tests pass.
IMPORTANT: Always assign to
@$usernames! You may be tempted to save a few keystrokes by writingbut 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
set_retval_scalar. Doing it this way would be both incorrect and misleading, a nasty combination.For completeness, a full working example is below.
Output: