While developing a plugin for Dancer as a wrapper around one of my modules, I wanted to unit test my code using a mock database instead of the database I do interactive tests with. Surprisingly, I didn't find documentation on how to supply Dancer::Plugin::Database with your own test database.

After some reading through the test suite of Dancer::Plugin::Database, it seems that the magic is in overwriting the configuration at the right time. To give this approach a broader exposure and to maybe invite some comments or better suggestions, let's look through the code:

In the prelude, we load Dancer, Dancer::Test and the application I'm writing, tentatively named mychat. We plan for three tests:

#!perl -w use strict; use warnings; use Test::More import => ['!pass']; use Data::Dumper; use Dancer ':syntax'; use DBIx::RunSQL; use Dancer::Plugin::Database; # the order is important use mychat; use Dancer::Test; plan tests => 3;

Then, we set up our own in-memory database and create all tables and triggers from the SQL file stored in sql/create.sql. This gives us a pristine database that contains only initial data.

# set up our own database instead of whatever is in the config my $conf = { Database => { dsn => 'dbi:SQLite:dbname=:memory:', connection_check_threshold => 0.1, sqlite_unicode => 1, dbi_params => { RaiseError => 0, PrintError => 0, PrintWarn => 0, }, }, }; set plugins => $conf; # Set up a fresh instance my $dbh = database; $dbh = DBIx::RunSQL->create( dbh => $dbh, sql => 'sql/create.sql', );

Since what I really want to test is whether image upload and retrieval works, let's fake a PNG image and "upload" it into the application:

my $payload = join '', "\x89", 'PNG', "\x0d\x0a", "\x1a", "\x0a", (map { chr($_) x (1024 * 256) } 1..3) ; # Insert image into database my $upload = Dancer::Request::Upload->new( filename => 'test.png', tempname => 'test2.png', size => length($payload), headers => { 'Content-Type' => 'image/png', }, ); # Insert into DB my $content = mychat::UserContent->store( config->{image_store}, $dbh, $upload, { extension => 'png', content_type => 'image/png', }, $payload );

After all this setup, we can now run three tests as if we had a standard Dancer application and can check that URLs exist where we expect them and that we get the appropriate content from each URL:

ok $content, "We successfully saved the user content"; route_exists(['GET', '/image_store/foo.bar'], "We find /image_store/fo +o.bar"); # Check that we can access it through /image_store/sha1.jpg my $name = $content->{digest} . ".png"; response_status_is ['GET',"/image_store/$name"], 200, "GET '/image_sto +re/$name' succeeds" or diag Dumper read_logs();