多次使用Test :: MockDBI,结果不同

vir*_*tor 6 database testing perl

我正在尝试在不同情况下测试一些代码(针对不同的结果集).我的第一个测试运行良好,但下一个测试是尝试重用第一个"表".

我的结果集:

my $usernames_many = [
      { username => '1234567' },
      { username => '2345678' },
   ];
my $usernames_empty = [
   ];
Run Code Online (Sandbox Code Playgroud)

但现在当我尝试这些电话时:

$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");
Run Code Online (Sandbox Code Playgroud)

第一次测试通过,但第二次测试结果如下:

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
Run Code Online (Sandbox Code Playgroud)

这似乎表明第一个结果集再次被使用.我该如何清理结果集?或者以其他方式重置状态?

Gre*_*con 1

乍一看,其实施可能令人沮丧set_retval_scalar

\n\n
sub set_retval_scalar {\n    my $self   = shift;                 # my blessed self\n    my $type   = shift;                 # type number from --dbitest=TYPE\n    my $sql    = shift;                 # SQL pattern for badness\n\n    push @{ $scalar_retval{$type} },\n     { "SQL" => $sql, "retval" => $_[0] };\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

第一个结果集似乎再次被使用的原因是连续调用是set_retval_scalar累积。在第二次调用之后set_retval_scalar,就在第二次测试之前, Test::MockDBI 的内部簿记类似于

\n\n
[ # first resultset\n  { SQL => "SELECT username ...",\n    retval => [{ username => \'1234567\' }, ...]\n  },\n  # second resultset\n  { SQL => "SELECT username ...",\n    retval => []\n  }\n]\n
Run Code Online (Sandbox Code Playgroud)\n\n

当您的第二个测试查询时SELECT username ..._force_retval_scalar在 Test::MockDBI 中,在该数据结构中搜索当前正在执行的查询,并在找到的第一个命中时停止。两个结果集都与同一查询关联,因此第二个结果集没有机会匹配。

\n\n

但还有希望!请注意,set_retval_scalar仅复制最外层引用\xe2\x80\x94a 对您控制的数组的引用!

\n\n

稍微修改你的测试:

\n\n
my @usernames_many = (\n  { username => \'1234567\' },\n  { username => \'2345678\' },\n);\n\nmy @usernames_empty = ();\n\nmy $usernames = [];\n$mock_dbi->set_retval_scalar(\n  MOCKDBI_WILDCARD,\n  "SELECT username FROM location",\n  $usernames);\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用此装置,您只需更改 的内容@$usernames(即引用的数组$usernames)即可更改查询的预设结果:

\n\n
@$usernames = @usernames_many;\nis_deeply(find_multiple_registrations($mock_db, 15),\n          [ \'1234567\', \'2345678\' ],\n          "many entries");\n\n@$usernames = @usernames_empty;\nis_deeply(find_multiple_registrations($mock_db, 15),\n          [ ],\n          "no entries");\n
Run Code Online (Sandbox Code Playgroud)\n\n

通过这些修改,两项测试都通过了。

\n\n

重要提示:始终分配给@$usernames!您可能会想通过编写来节省一些击键次数

\n\n
$usernames = [];  # empty usernames\nis_deeply(find_multiple_registrations($mock_db, 15),\n          [ ],\n          "no entries");\n
Run Code Online (Sandbox Code Playgroud)\n\n

但这将导致您的测试失败,原因与您的问题中的测试几乎相同:夹具将继续具有您在调用中给它的相同引用set_retval_scalar。这样做既不正确又具有误导性,是一种令人讨厌的组合。

\n\n
\n\n

为了完整起见,下面是一个完整的工作示例。

\n\n
#! /usr/bin/perl\n\nuse warnings;\nuse strict;\n\nBEGIN { push @ARGV, "--dbitest" }\n\nuse Test::MockDBI qw/ :all /;\nuse Test::More tests => 2;\n\nmy @usernames_many = (\n      { username => \'1234567\' },\n      { username => \'2345678\' },\n   );\nmy @usernames_empty = ();\n\nmy $usernames = [];\n\nmy $mock_dbi = get_instance Test::MockDBI;\nmy $mock_db = DBI->connect("dbi:SQLite:dbname=:memory:", "", "");\n$mock_db->{RaiseError} = 1;\n$mock_db->do(q{CREATE TABLE location (username char(10))});\n\nsub find_multiple_registrations {\n  my($dbh,$limit) = @_;\n  my $sth = $dbh->prepare("SELECT username FROM location");\n  $sth->execute;\n  [ map $_->{username} => @{ $sth->fetchall_arrayref } ];\n}\n\n$mock_dbi->set_retval_scalar(\n  MOCKDBI_WILDCARD,\n  "SELECT username FROM location",\n  $usernames);\n\n@$usernames = @usernames_many;\nis_deeply(find_multiple_registrations($mock_db, 15),\n          [ \'1234567\', \'2345678\' ],\n          "many entries");\n\n@$usernames = ();\nis_deeply(find_multiple_registrations($mock_db, 15),\n          [ ],\n          "no entries");\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出:

\n\n
1..2\n\nconnect() \'连接到 dbi:SQLite:dbname=:memory: 与 \'\n\ndo() \'创建表位置(用户名 char(10))\'\n\ nprepare() \'从位置选择用户名\'\n\nexecute()\n\nfetchall_arrayref()\nok 1 - 许多条目\n\nprepare() \'从位置选择用户名\'\n\nexecute()\ n\nfetchall_arrayref()\nok 2 - 没有条目
\n