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

单元测试脚本应该是独立的、无状态的且没有副作用。这些理想并不总是能够实现,但通过使用模拟对象等工具,我们通常可以接近这些理想。但是,某些功能比其他功能更难测试;例如,如何测试数据库接口代码?数据库有状态——即使你在测试之后重置了数据,也无法保证数据是相同的,或者其他代码在测试执行期间没有访问数据库。
处理这个问题的一种方法是为单元测试过程创建一个内存数据库,该数据库在测试完成后自动删除。幸运的是,使用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::Loader的dbicdump
命令来自动为你生成它们。
不仅仅是为了测试
SQLite的内存功能由DBI驱动程序DBD::SQLite提供,这是一个很酷的功能,可以用于更多比单元测试。任何你需要临时关系型数据存储的时候,考虑一下这个;它速度快,可移植,程序结束时自动清理。
这篇文章最初发布在PerlTricks.com。
标签
反馈
这篇文章有什么问题吗?通过在GitHub上打开问题或拉取请求来帮助我们。