En mi aplicación, hay una clase para cada modelo que contiene consultas de uso común (supongo que es algo así como un "Repositorio" en lenguaje DDD). Cada una de estas clases se pasa al objeto de sesión SQLAlchemy para crear consultas durante la construcción. Tengo un poco de dificultad para determinar la mejor forma de afirmar que ciertas consultas se están ejecutando en mis pruebas unitarias. Utilizando el ejemplo de blog ubicuo, digamos que tengo un modelo "Publicar" con columnas y atributos "fecha" y "contenido". También tengo un "PostRepository" con el método "find_latest" que se supone que consulta todas las publicaciones en orden descendente por "fecha". Se ve algo como:Python SQLAlchemy: simulando el método "desc" de un atributo de modelo
from myapp.models import Post
class PostRepository(object):
def __init__(self, session):
self._s = session
def find_latest(self):
return self._s.query(Post).order_by(Post.date.desc())
Tengo problemas para burlarse de la llamada Post.date.desc(). En este momento soy mono parcheando un simulacro de Post.date.desc en mi prueba de unidad, pero creo que es probable que haya un mejor enfoque.
Editar: Estoy usando mox de objetos simulados, mi prueba de la unidad actual se ve algo como:
import unittest
import mox
class TestPostRepository(unittest.TestCase):
def setUp(self):
self._mox = mox.Mox()
def _create_session_mock(self):
from sqlalchemy.orm.session import Session
return self._mox.CreateMock(Session)
def _create_query_mock(self):
from sqlalchemy.orm.query import Query
return self._mox.CreateMock(Query)
def _create_desc_mock(self):
from myapp.models import Post
return self._mox.CreateMock(Post.date.desc)
def test_find_latest(self):
from myapp.models.repositories import PostRepository
from myapp.models import Post
expected_result = 'test'
session_mock = self._create_session_mock()
query_mock = self._create_query_mock()
desc_mock = self._create_desc_mock()
# Monkey patch
tmp = Post.date.desc
Post.date.desc = desc_mock
session_mock.query(Post).AndReturn(query_mock)
query_mock.order_by(Post.date.desc().AndReturn('test')).AndReturn(query_mock)
query_mock.offset(0).AndReturn(query_mock)
query_mock.limit(10).AndReturn(expected_result)
self._mox.ReplayAll()
r = PostRepository(session_mock)
result = r.find_latest()
self._mox.VerifyAll()
self.assertEquals(expected_result, result)
Post.date.desc = tmp
Esto trabajo, aunque se siente feo y no estoy seguro de por qué no funciona sin la "AndReturn ('prueba') "pieza de" Post.date.desc(). AndReturn ('prueba') "
Eso tiene mucho sentido, estaba demasiado pendiente de los detalles del código. Gracias por la visión. –
Lo que está diciendo es que en lugar de hacer una prueba unitaria (una unidad de lógica), realice una prueba de integración (con la base de datos). Es un enfoque válido, y posiblemente el más sensato para un ORM, sin embargo, la realización de estas pruebas sufre una melodía de una o dos magnitudes. ¿Derecha? –
Tiene razón al escribir una prueba (ya sea que desee llamarla prueba de "unidad" o prueba de "integración") que de alguna manera accederá a un recurso más lento (ya sea una unidad de disco, servicio externo o base de datos) significará una prueba más lenta que una que no tiene acceso a dicho recurso. –