"DBI connect failed" when the test suite has no production credentials: choosing between DBD::Mock and skip_all
0 reputation · 31 Dec 2022, 08:05 UTC
0 reputation · 31 Dec 2022, 08:05 UTC
My Perl application connects through DBI at startup, and I want its integration test suite to run in CI and on developer machines where production database credentials are deliberately unavailable. Right now any run without a reachable database ends in DBI connect(...) failed, which makes the whole suite report as a failure even though the environment is intentionally unconfigured.
I am weighing two documented approaches. One is replacing the handle with DBD::Mock so prepare/execute return canned result sets and no real connection is attempted. The other is keeping the real connection path but gating it on environment variables such as TEST_DB_DSN, and calling skip_all from Test::More when they are missing, so the suite reports as skipped instead of failed.
My concern is that a fully mocked handle may hide driver-specific SQL errors, while the skip approach means most environments never exercise the database layer at all. Assume a current Perl 5 with DBI, DBD::Mock, and Test::More, verified locally with prove -v.
Which failure mode should the suite prefer when credentials are absent: a documented skip, or a mocked connection? Is there a standard way to combine both so mocked tests always run and live-database tests run only when a disposable DSN is provided? Should a missing-credentials run ever be a hard failure rather than a skip?
When a test run has no production database credentials, the preferred behaviour is to skip the tests that need a real database rather than let a hard connection failure surface. The real DBI code path should only be exercised when an explicit test DSN is supplied. For unit‑level tests that only need to exercise SQL generation, a DBD::Mock handle is acceptable, but those tests should be marked as mocked and not count as failures if the real database is unavailable.
use Test::More;
my $dsn = $ENV{TEST_DB_DSN} // '';
unless ($dsn) {
skip_all('No TEST_DB_DSN provided – skipping live‑DB tests');
}
DBD::Mock:
use DBD::Mock;
my $dbh = DBI->connect("dbi:Mock:dbname=test", undef, undef, {
RaiseError => 1,
AutoCommit => 1,
});
# set canned rows
$dbh->{Mock} = [ { id => 1, name => 'Alice' } ];
Only if the test suite is explicitly designed to run against a *known* disposable database (e.g. a Docker‑based test instance that is always started by the CI pipeline) should the absence of credentials be considered a hard failure. In most development workflows, however, a missing DSN should be a skip to avoid confusing developers and CI operators.
prove -v without TEST_DB_DSN and confirm that the output shows skipped for the relevant tests.TEST_DB_DSN to a lightweight SQLite DSN (e.g. dbi:SQLite:dbname=:memory:) and run prove -v again; the same tests should now be executed and pass or fail based on real DB behaviour.t/mock_sql.t) that never checks for TEST_DB_DSN.Use skip_all when no test DSN is available; use DBD::Mock only for isolated SQL‑generation tests. This hybrid approach keeps the test suite honest about configuration issues while still allowing thorough driver‑specific testing when a disposable database is supplied.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.