在内存数据库中测试您的代码

单元测试脚本应该是独立的、无状态的且没有副作用。这些理想并不总是能够实现,但通过使用模拟对象等工具,我们通常可以接近这些理想。但是,某些功能比其他功能更难测试;例如,如何测试数据库接口代码?数据库有状态——即使你在测试之后重置了数据,也无法保证数据是相同的,或者其他代码在测试执行期间没有访问数据库。

处理这个问题的一种方法是为单元测试过程创建一个内存数据库,该数据库在测试完成后自动删除。幸运的是,使用SQLite3和Perl来做这件事非常简单。

DBI

Perl的DBI模块是Perl中访问关系数据库的事实标准。为了创建一个内存数据库,我可以调用connect,指定SQLite驱动程序,并将数据库名称指定为“:memory:“。这返回一个指向新内存SQLite3数据库的数据库句柄。

use Test::More;
use DBI;

# load in-memory db
my $dbh = DBI->connect('dbi:SQLite:dbname=:memory:','','');

# create tables
my $create_table_script =
  do {  local $/; 
        open my $SQL, '<', 'create_tables.sql';
        <$SQL>;
     };  

my $sth = 
  $dbh->prepare($create_table_script) or BAIL_OUT ($dbh->errstr);
$sth->execute or BAIL_OUT($sth->errstr);

# add unit tests here ...

done_testing;

从这里,我将创建表的SQL脚本拖入一个字符串,并使用数据库句柄来执行它。如果数据库的任何步骤失败,将调用BAIL_OUT函数,提前结束测试。到目前为止,我已经有一个全新的数据库和新的表,准备进行测试。

DBIx::Class

DBIx::Class,Perl ORM使用与DBI相同的底层技术,但由于它为每个表创建代表Perl类的对象,我可以利用这些代码使数据库设置比使用纯DBI更容易。

use Test::More;
use SomeApp::Schema;

# load an in-memory database and deploy the required tables
SomeApp::Schema->connection('dbi:SQLite:dbname=:memory:','','');
SomeApp::Schema->load_namespaces;
SomeApp::Schema->deploy;

# add unit tests here ...

done_testing;

我使用一个名为SomeApp的示例应用程序来演示。首先,将connection设置与DBI示例中的相同数据库连接字符串。然后,使用load_namespaces方法加载应用程序中的所有结果和resultset DBIx::Class模块,并使用deploy在内存数据库中创建它们。显然,这种方法要求你已经创建了DBIx::Class文件。如果你还没有这样做,但你有包含表的应用程序数据库,你可以使用DBIx::Class::Schema::Loaderdbicdump命令来自动为你生成它们。

不仅仅是为了测试

SQLite的内存功能由DBI驱动程序DBD::SQLite提供,这是一个很酷的功能,可以用于更多比单元测试。任何你需要临时关系型数据存储的时候,考虑一下这个;它速度快,可移植,程序结束时自动清理。


这篇文章最初发布在PerlTricks.com

标签

David Farrell

David是一位专业程序员,他经常推文博客关于代码和编程的艺术。

查看他们的文章

反馈

这篇文章有什么问题吗?通过在GitHub上打开问题或拉取请求来帮助我们。