SilasTheMonk has asked for the wisdom of the Perl Monks concerning the following question:

I having some issues writing test scripts for CGI-Application-Plugin-PageLookup. The Makefile.PL lists DBI as a dependency but I do not state a dependency on any particular driver because of course it should not depend on any particular driver (or at least I would hope). In production I use DBD::mysql but my test scripts use DBD::SQLite. The test scripts are now generally failing because many test machines do not have DBD::SQLite installed. In fact I have failed to install DBD::SQLite on my production machine. So now I am looking for an alternative. mysql will not do because many machines (including my production machine) do not permit creating databases from scripts (or even via phpmyadmin). From the documentation I cannot see how one would use DBD::Sponge which is a shame since that ships with DBI itself. DBD::CSV looks promising but happens to be not installed on my production machine. It happens that I wrote a similar query to this sometime back writing DBI applications offline so I am reviewing that.

First question: Why would DBI be installed on a test machine but not a sensible driver? I cannot see a sensible answer to that even for test machines. The failing machines seem to support the following drivers: DBM, ExampleP, File, Gofer, Mock, Proxy, Sponge.

What are my options? I can think of the following:

  1. State that DBD::SQLite is a dependency. This seems to me a bad solution for simply being untrue.
  2. Put guards in my test scripts so that any test script depending on DBD::SQLite will simply skip. This seems to be the cleanest workable solution but sort of invalidates the testing for a lot of people.
  3. Several modules come up in the previous thread that I cannot see working: Mock, SQLite::Amalgamation. Could someone who has successfully used these please elaborate.
  4. DBD::Sponge and DBD:DBM look like they might work and come with DBI, but I am not sure.
  5. Test::MockDBI looks like it should work but I find the idea of trying to work out what SQL I am going to run really offputting. Specifically it is wrong headed. The whole reason I use a database is because the same data gets used multiple times and the SQL language allows me to state it once and query it from multiple angles. TestMockDBI seems to undermine that.
  6. I have had the idea of writing a DBD::TestVirtual driver. In setting this up you would state a list of real drivers in order of preference, and also hooks for creating, populating and destroying the test databases dynamically. The driver would try each of these in turn until it found one that worked and return a handle to that. Sounds cool until I think using it may be more hassle than Test::MockDBI.

I have the strong feeling I am going to regret posting this because somewhere up there I have answered my own question. At the very least it would be nice to know if other people have found similar issues and how they solved them.

  • Comment on How to write test scripts depending on DBI

Replies are listed 'Best First'.
Re: How to write test scripts depending on DBI
by ikegami (Patriarch) on Oct 05, 2009 at 19:49 UTC

    The test scripts are now generally failing because many test machines do not have DBD::SQLite installed.

    Add DBD::Sqlite to BUILD_REQUIRES to your Makefile.PL

    WriteMakefile( ... BUILD_REQUIRES => { "DBD::Sqlite" => 0 }, ... );
    Or make the test conditional on having DBD::Sqlite installed
    #!/usr/bin/perl -T use strict; use warnings; use Test::More; BEGIN { eval { require DBD::Sqlite } or plan skip_all => "This test requires DBD::Sqlite"; } ...

    From the documentation I cannot see how one would use DBD::Sponge

    When you create a DBI::Sponge statement handle, you specify the results fetch* will return:

    use DBI qw( ); my $dbh = DBI->connect('dbi:Sponge:'); my $sth = $dbh->prepare('SELECT * FROM Table', { NAME => [qw( id value )], rows => [ [ 1, 'foo' ], [ 2, 'bar' ], ], RaiseError => 1, }); $sth->execute(); # Does nothing while (my $row = $sth->fetch()) { print("$row->[0]: $row->[1]\n"); }
    1: foo 2: bar

    It's used to pass values to a sub which expects a statement handle without having to use a database.

      Aargh! The first two answers I understand and know how to do. I was more looking for defences and criticisms of them as solutions.

      If I understand DBD::Sponge correctly you cannot use a Sponge handle without knowing it is a Sponge. I thought the whole point of DBI is that once you have a DBI handle the perl code by and large does not need to know what the driver is (leaving aside issues of SQL dialect which obviously DBI can do nothing about.) As such I don't see why the Sponge module is in the DBD space let alone shipped with DBI. The same almost applies to DBD::Mock except that I can see some rather specialized applications for that. For example it might be useful to test a module that constructs SQL statements.

        I thought the whole point of DBI is that once you have a DBI handle the perl code by and large does not need to know what the driver is

        Ideally, yes, but it's overkill to write a database engine that parses and processes INSERT and SELECT statements if your goal is to produce statement handles that read arrays (something very useful, particularly to database drivers).

        As such I don't see why the Sponge module is in the DBD space let alone shipped with DBI.

        DBD::Sponge is usually used by other database drivers. As a building block for building database drivers, it is fitting for it to be in DBI.

        As such I don't see why the Sponge module is in the DBD space

        Where else would you put a DBD?

        I was more looking for defences and criticisms of them as solutions.

        DBD::Sponge: Unless you're testing a module that expects nothing but executed statement handles, not useful. Sorry, I thought I had made that obvious.

        DBD::Sqlite: No criticisms, thus my post. It's supported by popular ORMs, so it's excellent if your app/distro uses such an ORM.

        Why would DBI be installed on a test machine but not a sensible driver?

        Who cares. The installer handles all that for you.

        The question makes no sense anyway. A sensible driver for one purpose is not sensible for another. A particular driver that's sensible today won't be sensible tomorrow.

Re: How to write test scripts depending on DBI
by JavaFan (Canon) on Oct 05, 2009 at 19:27 UTC
    Will Test::Database do what you want? You can find it on your local CPAN mirror.
      Thanks. That looks genuinely promising; close enough to my DBD::TestVirtual to be affirming. And it is one I really had not heard of. I'll need to print off Test::Database::Tutorial and come back to thread. I even more interested now to see if anyone else has any ideas.