Test classes which interact with a database connection object.
DataAccessTestCase evolved to deal with some of the pitfalls associated with testing data access classes. The class also helps to simplify code by automating some repeated tasks.
Note that DataAccessTestCase will only work with the Aperiplus connection interface (see below). That probably limits the potential user-base to just one, me, but the underlying ideas may be of interest to other test-infected programmers and so here it is. Feel free to pinch anything for your own test framework.
<?php
interface Connection {
function query($sql);
function getRow($sql);
function getRows($sql);
function manipulateRows($sql);
function lastInsertId();
function getInfo();
function getError();
function ping();
function escape($string);
function close();
}
I have been using DataAccessTestCase for some time without problems but, if you decide to try it out, it's up to you to check the code as thoroughly as you need for your own purposes. The risk is that inadequate query authorisation code might allow non-fixture data to be altered. For example, faulty query authorisation logic could lead to the wrong database being dropped. If you look at the tests for SandboxParser classes (aperiplus/lib/tests/db-sandbox.php) you can see that I haven't covered every possible type of sql query.
Extend DataAccessTestCase:
<?php
class YourTests extends DataAccessTestCase {
...
...
}
The test case needs to be told about the db server. Add a "beforeInvoking()" method and call addHost, eg:
<?php
class YourTests extends DataAccessTestCase {
function beforeInvoking() {
$this->addHost(
'MysqliConnection',
'MysqlBigParser', // an sql parser class
'host',
'user',
'pass');
// optionally pass db name as sixth parameter
}
The first parameter is the name of a class which implements the Aperiplus Connection interface.
The second is an sql parser class. Parsers examine queries and translate these into appropriate authorisation objects. There are two types: one is used when you have the create database privilege and hence can set up fixtures by creating and dropping whole databases. However, you won't always be able to do this. For example, many budget hosting plans limit users to a single db. In this case fixture tables must be created and dropped within the named database. The two parser classes are called "MysqlBigParser" and "MysqlTinyParser" respectively. As you can see I hit a mental block when it came to naming...
With a "big" sandbox, you can optionally pass a database name. If given, the named database will automatically be created before each test and all connection objects provided by the framework will arrive using it. If not, you'll have to do all that yourself.
With a "tiny" sandbox, you must always pass a database name.
At present the only supported dbms is mysql. If you want to add support for another you'll need to write a new connection class and a new parser. Make sure they're included, and then pass the names in to addHost().
Currently you can only add a single host but in future versions I'll look at support for multiple hosts.
Special SandboxedConnection objects are provided for testing. They behave just like an ordinary connection except that they will decline any query which attempts to manipulate a non-fixture database (you'll get a "query not authorised" error).
One of these, the fixture tool, is used solely for fixture creation. Always use this to create the databases, tables, or rows of data required for a test fixture:
<?php
class YourTests extends DataAccessTestCase {
...
...
function setUp() {
$this->fxtool->query("create database foo");
$this->fxtool->query("create table foo.bar (a text)");
...
...
}
The fixture tool also provides some convenient methods to copy an existing schema, if present (all return boolean):
copyDatabaseStructure($from, $to)
copyDatabaseWithData($from, $to)
copyTableStructure($from, $to)
copyTableWithData($from, $to, $where = '')
Use getConnection() to obtain a fresh Connection object for each instance of the tested class. Each call to getConnection() returns a new object encapsulating a unique database link.
Note that all connections will automatically be closed by the framework; you won't need to do that manually.
<?php
class YourTests extends DataAccessTestCase {
...
...
function testSomething() {
$testable = new YourClass($this->getConnection());
...
...
}
By default, the connection object will connect using the account you gave in the addHost call. You can choose another:
<?php
function testSomething() {
$testable = new YourClass($this->getConnection('user', 'pass'));
...
...
}
At last, we can do some testing. You've got all the usual UnitTestCase & AperiTestCase assertions plus:
assertUsedDb(
$conn,
$db_name,
$message = '%s')assertDbNotUsed(
$conn,
$db_name,
$message = '%s')assertDatabase(
$db_name,
$message = '%s')assertNoDatabase(
$db_name,
$message = '%s')assertTables(
$db_name,
$table_list, - array
$message = '%s')assertTable(
$table_address, - dot syntax: "database.table"
$message = '%s')assertNoTable(
$table_address, - dot syntax: "database.table"
$message = '%s')assertNumRows(
$i,
$table_address, - dot syntax: "database.table"
$message = '%s')The test case will automatically tidy up after itself, deleting all fixture tables and databases, and closing all connections. You don't need a tearDown method unless you have other, non-database items to clean up.
Note that a fatal error in the tested class means that the test case will die before it gets a chance to clear up fixture databases and tables. To save you having to clear these up manually (new tests must always start from a clean slate) DataAccessTestCase will automatically detect and drop vestigial fixtures the next time the test script is run (in fact the next time any DataAccessTestCase is run: the same persistence mechansim is used for all and hence any DataAccessTestCase will remove vestigial fixtures left behind by any other DataAccessTestCase).
Skip conditions: