2010-09-11 13 views
9

Quiero asegurarme de que estoy probando Modelos/Objetos de forma aislada y no como un gran sistema.Cómo probar modelos en Django con claves externas

Si tengo un objeto de pedido y tiene claves externas para clientes, pagos, artículos de pedido, etc. y quiero probar la funcionalidad de pedido, necesito crear accesorios para todos esos datos relacionados, o crearlos en código. Creo que lo que realmente necesito hacer es burlarme de los otros elementos, pero no veo una solución fácil (o posible) para eso si estoy haciendo consultas en estos Foreign Keys.

Las soluciones comunes (accesorios) realmente no me dejan probar un objeto a la vez. Estoy seguro de que esto se debe en parte a que mi aplicación es manera sobre acoplado.

Estoy tratando de adoptar TDD como mi principal método de trabajo, pero la forma en que funcionan las cosas con Django, parece que se pueden ejecutar pruebas de unidad muy triviales, o estas pruebas de integración masiva.

[Editar] mejor ejemplo explícito y un poco más de humildad

Lo que quiero decir es que me parece para poder sólo para ejecutar pruebas unitarias triviales. He visto personas con módulos muy bien probados y granulares. Estoy seguro de que algo de esto se puede seguir hasta un diseño pobre.

Ejemplo:

que tiene un modelo de llamada Upsell que está vinculada a un modelo de producto. Luego tengo un modelo de Choices que son hijos de Upsell (¿quieres lo que está detrás de la puerta # 1, # 2, # 3).

El modelo Upsell tiene varios métodos que derivan elementos necesarios para representar la plantilla de sus elecciones. El más importante es que crea una URL para cada elección. Hace esto a través de la manipulación de cadenas, etc. Si quería probar el método Upsell.get_urls(), quiero que no dependa de los valores de las opciones en los dispositivos, y no quiero que dependa del valor de Producto en los accesorios.

Ahora llené el archivo db en el método setUp para las pruebas, y eso funciona bien con la forma en que Django rechaza la transacción cada vez, pero solo fuera de setUp y TearDown. Esto funciona bastante bien, excepto que algunos de los Modelos son bastante complejos de configurar, mientras que en realidad solo necesito obtener un atributo para ello.

No puedo darle un ejemplo de eso, ya que no puedo lograrlo, pero aquí está el tipo de cosas que estoy haciendo ahora. Básicamente ingresé un pedido completo, creé el experimento A/B al que estaba conectado, etc. Y eso sin contar Producto, Categorías, etc. todo configurado por accesorios. No es el trabajo extra lo que me preocupa, ya que ni siquiera puedo probar un objeto basado en la base de datos a la vez. Las pruebas a continuación son importantes, pero son pruebas de integración. Me gustaría crear algo así probando cada elemento por separado. Como usted señaló, tal vez no debería haber elegido un marco tan estrechamente relacionado con el DB. ¿Existe algún tipo de inyección de dependencia con algo como esto? (Más allá de mis pruebas, pero el código en sí, así)

class TestMultiSinglePaySwap(TestCase): 
    fixtures = ['/srv/asm/fixtures/alchemysites.json','/srv/asm/fixtures/catalog.json','/srv/asm/fixtures/checkout_smallset.json','/srv/asm/fixtures/order-test-fixture.json','/srv/asm/fixtures/offers.json'] 

def setUp(self): 
    self.o = Order() 
    self.sp = SiteProfile.objects.get(pk=1) 
    self.c = Customer.objects.get(pk=1) 
    signals.post_save.disconnect(order_email_first, sender=Order) 
    self.o.customer = self.c 
    p = Payment() 
    p.cc_number = '4444000011110000' 
    p.cc_exp_month = '12' 
    p.cc_type = 'V' 
    p.cc_exp_year = '2020' 
    p.cvv2 = '123' 
    p.save() 
    self.o.payment = p 
    self.o.site_profile = self.sp 
    self.o.save() 
    self.initial_items = [] 
    self.main_kit = Product.objects.get(pk='MOA1000D6') 
    self.initial_items.append(self.main_kit) 
    self.o.add_item('MOA1000D6', 1, False) 
    self.item1 = Product.objects.get(pk='MOA1041A-6') 
    self.initial_items.append(self.item1) 
    self.o.add_item('MOA1041A-6', 1, False) 
    self.item2 = Product.objects.get(pk='MOA1015-6B') 
    self.initial_items.append(self.item2) 
    self.o.add_item('MOA1015-6B', 1, False) 
    self.item3 = Product.objects.get(pk='STP1001-6E') 
    self.initial_items.append(self.item3) 
    self.o.add_item('STP1001-6E', 1, False) 
    self.swap_item1 = Product.objects.get(pk='MOA1041A-1') 

def test_single_pay_swap_wholeorder(self): 
    o = self.o 
    swap_all_skus(o) 
    post_swap_order = Order.objects.get(pk = o.id) 
    swapped_skus = ['MOA1000D','MOA1041A-1','MOA1015-1B','STP1001-1E'] 
    order_items = post_swap_order.get_all_line_items() 
    self.assertEqual(order_items.count(), 4) 
    pr1 = Product() 
    pr1.sku = 'MOA1000D' 
    item = OrderItem.objects.get(order = o, sku = 'MOA1000D') 
    self.assertTrue(item.sku.sku == 'MOA1000D') 
    pr2 = Product() 
    pr2.sku = 'MOA1015-1B' 
    item = OrderItem.objects.get(order = o, sku = 'MOA1015-1B') 
    self.assertTrue(item.sku.sku == 'MOA1015-1B') 
    pr1 = Product() 
    pr1.sku = 'MOA1041A-1' 
    item = OrderItem.objects.get(order = o, sku = 'MOA1041A-1') 
    self.assertTrue(item.sku.sku == 'MOA1041A-1') 
    pr1 = Product() 
    pr1.sku = 'STP1001-1E' 
    item = OrderItem.objects.get(order = o, sku = 'STP1001-1E') 
    self.assertTrue(item.sku.sku == 'STP1001-1E') 

Tenga en cuenta que nunca he utilizado realmente un marco Mock aunque he intentado. Así que también es posible que me esté perdiendo algo fundamentalmente aquí.

Respuesta

4

Esto probablemente no responderá a su pregunta, pero puede darle más que nada.

En mi opinión, cuando está probando un proyecto o aplicación respaldada por una base de datos, existe un límite para lo que puede simular. Esto es especialmente así cuando está usando un marco y un ORM como el que ofrece Django. En Django no hay distinción entre la clase de modelo de negocio y la clase de modelo de persistencia. Si desea una distinción así, tendrá que agregarla usted mismo.

A menos que esté dispuesto a agregar esa capa adicional de complejidad usted mismo se vuelve complicado probar los objetos de negocio solo sin tener que agregar accesorios, etc. Si tiene que hacerlo, tendrá que abordar parte del voidoo de magia automática realizado por Django.

Si elige arenar los dientes y excavar, el Python de Michael Foord Mock library será muy útil.

Estoy intentando mi darndest adoptar TDD como mi principal método de trabajo, pero la forma en que las cosas funcionen con Django, parece que puede ejecutar pruebas unitarias muy triviales, o estas pruebas de integración masivas.

He usado el mecanismo de prueba de la unidad Django para escribir pruebas de unidades no triviales. Mis requisitos eran, sin duda, muy diferentes de los tuyos. Si puede proporcionar detalles más específicos sobre lo que está tratando de lograr, los usuarios aquí podrían sugerir otras alternativas.

+1

Creo que cuando dijiste "no hay distinción entre la clase de modelo de negocio y la clase de modelo de persistencia", das en el clavo. Django le brinda la opción de base de datos de prueba y eso es lo más parecido a la burla que podría esperarse (aunque podría haber un backend db "simulado" que solo aplicaría las restricciones que desee). Al menos ahora sé que no estoy buscando algo que ya esté escrito. – zenWeasel

+0

También puede consultar el https://github.com/dcramer/mock-django de David Cramer. Por cierto, hay una bifurcación de la biblioteca simulada en github: https://github.com/yujiabe/mock (actualizado en junio) 2012) – Andrei

+0

FWIW, he adoptado el consejo de saltar con Mock y mock-django y he logrado mucho de lo que estaba intentando hacer. La biblioteca Mock requiere un poco de aprendizaje sobre cómo usarla correctamente, pero ha valido la pena. Así que solo quería actualizar que esos dos consejos eran correctos sobre el dinero y 2-3 años después uso esos métodos todos los días para escribir pruebas unitarias no triviales. – zenWeasel

3

Mire en model mommy. Puede crear automágicamente objetos con claves externas.

+0

Ese es mi siguiente paso. Donde trabajo ahora hacemos mucho menos pruebas de base de datos, pero estamos en una situación en la que definitivamente no podemos usar accesorios. Así que estoy buscando modelo-mamá y fábrica de cuerpo. – zenWeasel

Cuestiones relacionadas