Sugeriría burlarse de sus llamadas a la base de datos. Los simulacros son básicamente objetos que se parecen al objeto al que está intentando llamar un método, en el sentido de que tienen las mismas propiedades, métodos, etc. disponibles para la persona que llama. Pero en lugar de realizar cualquier acción para la que estén programados cuando se llama a un método en particular, lo omite por completo y solo devuelve un resultado. Ese resultado generalmente lo define usted con anticipación.
Para configurar sus objetos para burlarse, probablemente necesite usar algún tipo de inversión del patrón de inyección de control / dependencia, como en el siguiente pseudocódigo:
class Bar
{
private FooDataProvider _dataProvider;
public instantiate(FooDataProvider dataProvider) {
_dataProvider = dataProvider;
}
public getAllFoos() {
// instead of calling Foo.GetAll() here, we are introducing an extra layer of abstraction
return _dataProvider.GetAllFoos();
}
}
class FooDataProvider
{
public Foo[] GetAllFoos() {
return Foo.GetAll();
}
}
Ahora en su prueba de unidad, crea una simulación de FooDataProvider, que le permite llamar al método GetAllFoos sin tener que acceder a la base de datos.
class BarTests
{
public TestGetAllFoos() {
// here we set up our mock FooDataProvider
mockRepository = MockingFramework.new()
mockFooDataProvider = mockRepository.CreateMockOfType(FooDataProvider);
// create a new array of Foo objects
testFooArray = new Foo[] {Foo.new(), Foo.new(), Foo.new()}
// the next statement will cause testFooArray to be returned every time we call FooDAtaProvider.GetAllFoos,
// instead of calling to the database and returning whatever is in there
// ExpectCallTo and Returns are methods provided by our imaginary mocking framework
ExpectCallTo(mockFooDataProvider.GetAllFoos).Returns(testFooArray)
// now begins our actual unit test
testBar = new Bar(mockFooDataProvider)
baz = testBar.GetAllFoos()
// baz should now equal the testFooArray object we created earlier
Assert.AreEqual(3, baz.length)
}
}
Un escenario de burla común, en pocas palabras. Por supuesto, es probable que también desee probar la unidad de sus llamadas de base de datos reales, para lo cual deberá acceder a la base de datos.
Idealmente, sus objetos deben ser persistentes ignorantes. Por ejemplo, debe tener una "capa de acceso a datos", a la que haría solicitudes, que devolvería objetos. De esta manera, puede dejar esa parte fuera de las pruebas de su unidad, o probarlas de forma aislada.
Si sus objetos están estrechamente acoplados a su capa de datos, es difícil hacer una prueba de unidad adecuada. la primera parte de la prueba unitaria, es "unidad". Todas las unidades deben poder probarse de forma aislada.
En mis proyectos de C #, uso NHibernate con una capa de datos completamente separada. Mis objetos viven en el modelo de dominio central y se accede desde mi capa de aplicación. La capa de aplicación habla tanto con la capa de datos como con la capa del modelo de dominio.
La capa de aplicación también se denomina a veces la "capa empresarial".
Si está utilizando PHP, cree un conjunto específico de clases para SOLO acceso a datos. Asegúrese de que sus objetos no tengan idea de cómo son persistentes y conecte los dos en sus clases de aplicación.
Otra opción sería usar burlas / talones.
fuente
La forma más fácil de probar un objeto con acceso a la base de datos es mediante ámbitos de transacción.
Por ejemplo:
Esto revertirá el estado de la base de datos, básicamente como una reversión de transacción para que pueda ejecutar la prueba tantas veces como lo desee sin ningún efecto secundario. Hemos utilizado este enfoque con éxito en grandes proyectos. Nuestra construcción tarda un poco en ejecutarse (15 minutos), pero no es horrible tener 1800 pruebas unitarias. Además, si el tiempo de compilación es una preocupación, puede cambiar el proceso de compilación para que tenga varias compilaciones, una para construir src, otra que se activa luego que maneja pruebas unitarias, análisis de código, empaquetado, etc.
fuente
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.
fuente
Debe burlarse del acceso a la base de datos si desea probar sus clases de forma unitaria. Después de todo, no desea probar la base de datos en una prueba unitaria. Esa sería una prueba de integración.
Resuma las llamadas y luego inserte una simulación que solo devuelva los datos esperados. Si sus clases no hacen más que ejecutar consultas, quizás no valga la pena probarlas, sin embargo ...
fuente
El libro xUnit Test Patterns describe algunas formas de manejar el código de prueba de unidad que llega a una base de datos. Estoy de acuerdo con las otras personas que dicen que no quieres hacer esto porque es lento, pero debes hacerlo en algún momento, en mi opinión. Es una buena idea burlarse de la conexión db para probar cosas de nivel superior, pero consulte este libro para obtener sugerencias sobre cosas que puede hacer para interactuar con la base de datos real.
fuente
Opciones que tienes:
Inyectar la base de datos. (Ejemplo en pseudo-Java, pero se aplica a todos los lenguajes OO)
ahora en producción usa una base de datos normal y para todas las pruebas simplemente inyecta la base de datos simulada que puede crear ad hoc.User
lugar de una tupla{name: "marcin", password: "blah"}
) escriba todas sus pruebas con objetos reales construidos ad hoc y escriba una prueba grande que dependa de una base de datos que asegure esta conversión funciona bienPor supuesto, estos enfoques no son mutuamente excluyentes y puede mezclarlos y combinarlos según lo necesite.
fuente
La unidad que prueba el acceso a su base de datos es bastante fácil si su proyecto tiene una alta cohesión y un acoplamiento flojo. De esta manera, puede probar solo las cosas que hace cada clase en particular sin tener que probar todo a la vez.
Por ejemplo, si prueba su clase de interfaz de usuario, las pruebas que escriba solo deberían intentar verificar que la lógica dentro de la interfaz de usuario funcionó como se esperaba, no la lógica de negocios o la acción de la base de datos detrás de esa función.
Si desea realizar una prueba unitaria del acceso real a la base de datos, en realidad terminará con más de una prueba de integración, porque dependerá de la pila de red y su servidor de base de datos, pero puede verificar que su código SQL haga lo que le pidió. hacer.
El poder oculto de las pruebas unitarias para mí personalmente ha sido que me obliga a diseñar mis aplicaciones de una manera mucho mejor de lo que podría sin ellas. Esto se debe a que realmente me ayudó a romper con la mentalidad de "esta función debería hacer todo".
Lo siento, no tengo ningún ejemplo de código específico para PHP / Python, pero si desea ver un ejemplo de .NET, tengo una publicación que describe una técnica que solía hacer esta misma prueba.
fuente
Por lo general, trato de dividir mis pruebas entre probar los objetos (y ORM, si corresponde) y probar la base de datos. Pruebo el lado del objeto de las cosas burlándome de las llamadas de acceso a datos, mientras que pruebo el lado db de las cosas probando las interacciones del objeto con el db que, en mi experiencia, generalmente es bastante limitado.
Solía frustrarme con la escritura de pruebas unitarias hasta que empiezo a burlarme de la parte de acceso a datos para no tener que crear una base de datos de prueba o generar datos de prueba sobre la marcha. Al burlarse de los datos, puede generarlos todos en tiempo de ejecución y asegurarse de que sus objetos funcionan correctamente con entradas conocidas.
fuente
Nunca he hecho esto en PHP y nunca he usado Python, pero lo que quieres hacer es burlarte de las llamadas a la base de datos. Para hacer eso, puede implementar alguna IoC, ya sea una herramienta de terceros o administrarla usted mismo, luego puede implementar alguna versión simulada de la persona que llama la base de datos, que es donde controlará el resultado de esa llamada falsa.
Se puede realizar una forma simple de IoC simplemente codificando en Interfaces. Esto requiere algún tipo de orientación de objeto en su código, por lo que puede que no se aplique a lo que está haciendo (lo digo porque todo lo que tengo que seguir es su mención de PHP y Python)
Espero que sea útil, si nada más, tiene algunos términos para buscar ahora.
fuente
Estoy de acuerdo con el primer post: el acceso a la base de datos debe eliminarse en una capa DAO que implemente una interfaz. Luego, puede probar su lógica contra una implementación de código auxiliar de la capa DAO.
fuente
Podrías usar marcos burlones para abstraer el motor de la base de datos. No sé si PHP / Python obtuvo algo, pero para los lenguajes mecanografiados (C #, Java, etc.) hay muchas opciones
También depende de cómo diseñó esos códigos de acceso a la base de datos, porque algunos diseños son más fáciles de probar que otros, como se mencionó en las publicaciones anteriores.
fuente
Configurar datos de prueba para pruebas unitarias puede ser un desafío.
Cuando se trata de Java, si usa Spring API para pruebas unitarias, puede controlar las transacciones a nivel de unidad. En otras palabras, puede ejecutar pruebas unitarias que implican actualizaciones / inserciones / eliminaciones de bases de datos y deshacer los cambios. Al final de la ejecución, deja todo en la base de datos como estaba antes de comenzar la ejecución. Para mí, es tan bueno como puede ser.
fuente