Tal vez pueda darle una idea de nuestra experiencia cuando comenzamos a analizar las pruebas unitarias de nuestro proceso de nivel medio que incluía un montón de operaciones sql de "lógica de negocios".
Primero creamos una capa de abstracción que nos permitía "insertar" cualquier conexión de base de datos razonable (en nuestro caso, simplemente admitíamos una única conexión de tipo ODBC).
Una vez que esto estuvo en su lugar, pudimos hacer algo así en nuestro código (trabajamos en C ++, pero estoy seguro de que entiende la idea):
GetDatabase (). ExecuteSQL ("INSERTAR EN foo (bla, bla)")
En tiempo de ejecución normal, GetDatabase () devolvería un objeto que alimentaba todos nuestros sql (incluidas las consultas), a través de ODBC directamente a la base de datos.
Luego comenzamos a buscar en las bases de datos en memoria: el mejor, en gran medida, parece ser SQLite. ( http://www.sqlite.org/index.html ). Es notablemente simple de configurar y usar, y nos permitió subclasificar y anular GetDatabase () para reenviar sql a una base de datos en memoria que se creó y destruyó para cada prueba realizada.
Todavía estamos en las primeras etapas de esto, pero hasta ahora se ve bien, sin embargo, debemos asegurarnos de crear las tablas que sean necesarias y llenarlas con datos de prueba; sin embargo, hemos reducido la carga de trabajo aquí al crear Un conjunto genérico de funciones auxiliares que puede hacer mucho de todo esto por nosotros.
En general, ha ayudado enormemente con nuestro proceso TDD, ya que realizar cambios que parecen bastante inocuos para corregir ciertos errores puede tener efectos bastante extraños en otras áreas (difíciles de detectar) de su sistema, debido a la naturaleza misma de SQL / bases de datos.
Obviamente, nuestras experiencias se han centrado en un entorno de desarrollo de C ++, sin embargo, estoy seguro de que quizás podría obtener algo similar trabajando en PHP / Python.
Espero que esto ayude.