database - 多次使用 Test::MockDBI 得到不同的结果

标签 database perl testing

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

我的结果集:

my $usernames_many = [
      { username => '1234567' },
      { username => '2345678' },
   ];
my $usernames_empty = [
   ];

但是现在当我尝试这些调用时:

$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");

第一个测试通过,但第二个结果:

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

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

最佳答案

implementation of set_retval_scalar 乍一看可能令人沮丧:

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] };
}

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

[ # first resultset
  { SQL => "SELECT username ...",
    retval => [{ username => '1234567' }, ...]
  },
  # second resultset
  { SQL => "SELECT username ...",
    retval => []
  }
]

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

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

稍微修改你的测试:

my @usernames_many = (
  { username => '1234567' },
  { username => '2345678' },
);

my @usernames_empty = ();

my $usernames = [];
$mock_dbi->set_retval_scalar(
  MOCKDBI_WILDCARD,
  "SELECT username FROM location",
  $usernames);

有了这个fixture,你只需要改变@$usernames的内容(即$usernames引用的数组)更改查询的固定结果:

@$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");

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

重要:始终分配给 @$usernames!您可能想通过书写来节省几次击键

$usernames = [];  # empty usernames
is_deeply(find_multiple_registrations($mock_db, 15),
          [ ],
          "no entries");

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


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

#! /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");

输出:

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

关于database - 多次使用 Test::MockDBI 得到不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3511268/

相关文章:

java - 使用fragment_Tabbed Activity 将数据保存到Sqlite 数据库

sql-server - SQL Server 到 Oracle10g 的转换

perl - 如何使用 perl Archive::Zip 将文件添加到存档?

perl - 使用 DBIx::Class 的多对多访问器

angular - Typescript - Angular 测试,如何使用 ngOnInit 中的参数处理 http 请求?

.net - .Net 中的数据库应用程序最佳实践

database - 匹配模糊字符串

linux - 删除文件中行之间的字符串

ruby-on-rails - MiniTest 模型验证测试失败

ruby-on-rails-3 - 使用 RSpec 测试范围质量分配